Получение атрибутов класса - PullRequest
68 голосов
/ 30 января 2012

Я хочу получить атрибуты класса, скажем:

class MyClass():
  a = "12"
  b = "34"

  def myfunc(self):
    return self.a

с использованием MyClass.__dict__ дает мне список атрибутов и функций, и даже таких функций, как __module__ и __doc__.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 100 * * * * * * * * * * * * * * * * * * * * * *1001* * * * * * * * *

.

Ответы [ 15 ]

88 голосов
/ 30 января 2012

Попробуйте проверить модуль. getmembers и различные тесты должны быть полезны.

EDIT:

Например,

class MyClass(object):
    a = '12'
    b = '34'
    def myfunc(self):
        return self.a

>>> import inspect
>>> inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a)))
[('__class__', type),
 ('__dict__',
  <dictproxy {'__dict__': <attribute '__dict__' of 'MyClass' objects>,
   '__doc__': None,
   '__module__': '__main__',
   '__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
   'a': '34',
   'b': '12',
   'myfunc': <function __main__.myfunc>}>),
 ('__doc__', None),
 ('__module__', '__main__'),
 ('__weakref__', <attribute '__weakref__' of 'MyClass' objects>),
 ('a', '34'),
 ('b', '12')]

Теперь специальные методы и атрибуты действуют мне на нервы - с ними можно справиться разными способами, самый простой из которых - просто фильтровать по имени.

>>> attributes = inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a)))
>>> [a for a in attributes if not(a[0].startswith('__') and a[0].endswith('__'))]
[('a', '34'), ('b', '12')]

... и более сложный из которых может включать специальные проверки имен атрибутов или даже метаклассы;)

29 голосов
/ 22 июня 2013
def props(cls):   
  return [i for i in cls.__dict__.keys() if i[:1] != '_']

properties = props(MyClass)
17 голосов
/ 30 января 2012

myfunc является атрибутом MyClass.Вот как он обнаруживается при запуске:

myinstance = MyClass()
myinstance.myfunc()

Он ищет атрибут на myinstance с именем myfunc, не находит его, видит, что myinstance является экземпляром MyClass иищет его там.

Итак, полный список атрибутов для MyClass:

>>> dir(MyClass)
['__doc__', '__module__', 'a', 'b', 'myfunc']

(Обратите внимание, что я использую dir просто как быстрыйи простой способ составить список членов класса: его следует использовать только в ознакомительном режиме, а не в рабочем коде)

Если вам нужны только определенные атрибуты, вам нужно отфильтровать этот список по некоторым критериямпотому что __doc__, __module__ и myfunc не являются чем-то особенным, они являются атрибутами точно так же, как a и b.

Я имеюникогда не использовал модуль проверки, на который ссылаются Мэтт и Бореалид, но из краткой ссылки видно, что у него есть тесты, которые помогут вам в этом, но вам нужно написать свою собственную функцию предиката, так как кажется, что вы хотите примерноатрибуты, которые не проходят тест isroutine и не запускаютсяи заканчиваются двумя подчеркиваниями.

Также обратите внимание: при использовании class MyClass(): в Python 2.7 вы используете крайне устаревшие классы старого стиля.Если вы не делаете это специально для совместимости с очень старыми библиотеками, вместо этого вы должны определить свой класс как class MyClass(object):.В Python 3 нет классов "старого стиля", и это поведение по умолчанию.Однако использование классов newstyle даст вам lot более автоматически определенных атрибутов:

>>> class MyClass(object):
        a = "12"
        b = "34"
        def myfunc(self):
            return self.a
>>> dir(MyClass)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'myfunc']
6 голосов
/ 30 января 2012

MyClass().__class__.__dict__

Однако «правильным» было сделать это через модуль проверки .

3 голосов
/ 28 июля 2017

Получить только атрибуты экземпляра легко.
Но получить атрибуты класса без функций немного сложнее.

Только атрибуты экземпляра

Если вам нужно только перечислить атрибуты экземпляра , просто используйте
for attribute, value in my_instance. __dict__. items()

>>> from __future__ import (absolute_import, division, print_function)
>>> class MyClass(object):
...   def __init__(self):
...     self.a = 2
...     self.b = 3
...   def print_instance_attributes(self):
...     for attribute, value in self.__dict__.items():
...       print(attribute, '=', value)
...
>>> my_instance = MyClass()
>>> my_instance.print_instance_attributes()
a = 2
b = 3
>>> for attribute, value in my_instance.__dict__.items():
...   print(attribute, '=', value)
...
a = 2
b = 3

Экземпляры и атрибуты класса

Чтобы получить также атрибуты класса без функций, уловка заключается в использовании callable().

Но статические методы не всегда callable!

Поэтому вместо использования callable(value) используйте
callable (getattr (MyClass, attribute))

Пример * * тысяча пятьдесят-две from __future__ import (absolute_import, division, print_function) class MyClass(object): a = "12" b = "34" # class attributes def __init__(self, c, d): self.c = c self.d = d # instance attributes @staticmethod def mystatic(): # static method return MyClass.b def myfunc(self): # non-static method return self.a def print_instance_attributes(self): print('[instance attributes]') for attribute, value in self.__dict__.items(): print(attribute, '=', value) def print_class_attributes(self): print('[class attributes]') for attribute in MyClass.__dict__.keys(): if attribute[:2] != '__': value = getattr(MyClass, attribute) if not callable(value): print(attribute, '=', value) v = MyClass(4,2) v.print_class_attributes() v.print_instance_attributes() Примечание: print_class_attributes() должно быть @staticmethod
& ЕПРС; & ЕПРС; но не в этом глупом и простом примере. Результат для

$ python2 ./print_attributes.py
[class attributes]
a = 12
b = 34
[instance attributes]
c = 4
d = 2

Тот же результат для

$ python3 ./print_attributes.py
[class attributes]
b = 34
a = 12
[instance attributes]
c = 4
d = 2
2 голосов
/ 24 апреля 2018

Я не знаю, было ли сделано что-то подобное сейчас или нет, но я сделал хорошую функцию поиска атрибутов, используя vars (). vars () создает словарь атрибутов класса, через который вы проходите.

class Player():
    def __init__(self):
        self.name = 'Bob'
        self.age = 36
        self.gender = 'Male'

s = vars(Player())
#From this point if you want to print all the attributes, just do print(s)

#If the class has a lot of attributes and you want to be able to pick 1 to see
#run this function
def play():
    ask = input("What Attribute?>: ")
    for key, value in s.items():
        if key == ask:
            print("self.{} = {}".format(key, value))
            break
    else:
        print("Couldn't find an attribute for self.{}".format(ask))

Я занимаюсь разработкой довольно масштабного Text Adventure на Python, мой класс Player на данный момент имеет более 100 атрибутов. Я использую это для поиска определенных атрибутов, которые мне нужно увидеть.

2 голосов
/ 20 октября 2016
import re

class MyClass:
    a = "12"
    b = "34"

    def myfunc(self):
        return self.a

attributes = [a for a, v in MyClass.__dict__.items()
              if not re.match('<function.*?>', str(v))
              and not (a.startswith('__') and a.endswith('__'))]

Для экземпляра MyClass, такого как

mc = MyClass()

, используйте type(mc) вместо MyClass в понимании списка.Однако, если кто-то динамически добавляет атрибут к mc, такой как mc.c = "42", атрибут не будет отображаться при использовании type(mc) в этой стратегии.Он только дает атрибуты исходного класса.

Чтобы получить полный словарь для экземпляра класса, вам нужно СОЕДИНИТЬ словари type(mc).__dict__ и mc.__dict__.

mc = MyClass()
mc.c = "42"

# Python 3.5
combined_dict = {**type(mc).__dict__, **mc.__dict__}

# Or Python < 3.5
def dict_union(d1, d2):
    z = d1.copy()
    z.update(d2)
    return z

combined_dict = dict_union(type(mc).__dict__, mc.__dict__)

attributes = [a for a, v in combined_dict.items()
              if not re.match('<function.*?>', str(v))
              and not (a.startswith('__') and a.endswith('__'))]
1 голос
/ 21 августа 2018

Думаю, это можно сделать без проверки.

Возьмите следующий класс:

 class Test:
   a = 1
   b = 2

   def __init__(self):
     self.c = 42

   @staticmethod
   def toto():
     return "toto"

   def test(self):
     return "test"

Глядя на участников вместе с их типами:

t = Test()
l = [ (x, eval('type(x.%s).__name__' % x)) for x in dir(a) ]

... дает:

[('__doc__', 'NoneType'),
 ('__init__', 'instancemethod'),
 ('__module__', 'str'),
 ('a', 'int'),
 ('b', 'int'),
 ('c', 'int'),
 ('test', 'instancemethod'),
 ('toto', 'function')]

Таким образом, чтобы вывести только переменные, вам просто нужно отфильтровать результаты по типу, а имена не начинаются с '__'. Э.Г.

filter(lambda x: x[1] not in ['instancemethod', 'function'] and not x[0].startswith('__'), l)

[('a', 'int'), ('b', 'int'), ('c', 'int')] # actual result

Вот и все.

Примечание: если вы используете Python 3, преобразуйте итераторы в списки.

Если вы хотите более надежный способ сделать это, используйте inspect .

1 голос
/ 13 апреля 2018

Вы можете использовать dir() в списке , чтобы получить имена атрибутов:

names = [p for p in dir(myobj) if not p.startswith('_')]

Используйте getattr(), чтобы получить сами атрибуты:

attrs = [getattr(myobj, p) for p in dir(myobj) if not p.startswith('_')]
1 голос
/ 09 марта 2016

Мне недавно нужно было выяснить что-то похожее на этот вопрос, поэтому я хотел опубликовать некоторую справочную информацию, которая может быть полезна для других, сталкивающихся с тем же в будущем.

Вот как это работает в Python (из https://docs.python.org/3.5/reference/datamodel.html#the-standard-type-hierarchy):

MyClass является объектом класса, MyClass() является экземпляром объекта класса. __dict__ экземпляра содержит только атрибуты и методы, специфичные для этого экземпляра (например, self.somethings). Еслиатрибут или метод является частью класса, он находится в __dict__ класса. Когда вы делаете MyClass().__dict__, создается экземпляр MyClass без атрибутов или методов, кроме атрибутов класса, таким образом, пустой __dict__

Итак, если вы скажете print(MyClass().b), Python сначала проверяет dict нового экземпляра MyClass().__dict__['b'] и не может найти b. Затем он проверяет класс MyClass.__dict__['b'] и находит b.

Вот почему вам нужен модуль inspect, чтобы эмулировать тот же процесс поиска.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...