Получение атрибутов класса
Я хочу получить атрибуты класса, скажем:
class MyClass():
a = "12"
b = "34"
def myfunc(self):
return self.a
используя MyClass.__dict__ дает мне список атрибутов и функций, и даже такие функции, как __module__ и __doc__. В то время как MyClass().__dict__ дает мне пустой dict, если я явно не задал значение атрибута этого экземпляра.
Я просто хочу атрибуты, в приведенном выше примере это будет:a и b
14 ответов:
попробовать проверить модуль.
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')]...и более сложные из которых могут включать специальные проверки имен атрибутов или даже метаклассы;)
myfuncи атрибутMyClass. Вот как это обнаруживается при запуске:myinstance = MyClass() myinstance.myfunc()он ищет атрибут
myinstanceимениmyfunc, не находит, видит, чтоmyinstanceпримерMyClassи смотрит его там.так полное список атрибутов
MyClass- это:>>> dir(MyClass) ['__doc__', '__module__', 'a', 'b', 'myfunc'](обратите внимание, что я использую dir просто как быстрый и простой способ перечислить членов класса: это должно быть только используется в исследовательском режиме, а не в производственном коде)
Если вам нужны только определенные атрибуты, вам нужно будет отфильтровать этот список, используя некоторые критерии, потому что
__doc__,__module__иmyfuncне спец в любом случае, они атрибуты точно так же, какaиbесть.я никогда не использовал модуль inspect, упомянутый Matt и Borealid, но из краткой ссылки похоже, что у него есть тесты, которые помогут вам это сделать, но вам нужно будет написать ваша собственная функция предиката, так как кажется, что вы хотите, это примерно атрибуты, которые не передать
isroutineпроверьте и не начинайте и не заканчивайте двумя подчеркиваниями.обратите внимание: с помощью
class MyClass():в Python 2.7 вы используете дико устаревшие классы старого стиля. Если вы не делаете это намеренно для совместимости с очень старыми библиотеками, вы должны вместо этого определить свой класс какclass MyClass(object):. В Python 3 нет классов "старого стиля", и это поведение по умолчанию. Однако, используя классы newstyle вы получите много более автоматически определенные атрибуты:>>> 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']
MyClass().__class__.__dict__однако, "право" должно было сделать это через модуль проверить.
Я не знаю, было ли что-то подобное сделано сейчас или нет, но я сделал хорошую функцию поиска атрибутов с помощью 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))Я разрабатываю довольно массивное текстовое приключение в Python, мой класс игрока до сих пор имеет более 100 атрибутов. Я использую это для поиска конкретных атрибутов, которые мне нужно увидеть.
мое решение, чтобы получить все атрибуты (не методов) класса
def get_class_attrs(cls): return re.findall(r'\w+(?=[,\)])', cls.__dict__['__doc__'])
недавно мне нужно было выяснить что-то похожее на этот вопрос, поэтому я хотел опубликовать некоторую фоновую информацию, которая может быть полезна другим, столкнувшимся с тем же в будущем.
вот как это работает в 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модуль, чтобы повторить тот же самый процесс поиска.
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('__'))]
только атрибуты экземпляра легко.
Но получение также атрибуты класса без функций немного сложнее.атрибуты экземпляра только
если вы только должны перечислить атрибуты экземпляра просто использовать
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().но статические методы are не всегда
, вместо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
$ python2 ./print_attributes.py [class attributes] a = 12 b = 34 [instance attributes] c = 4 d = 2тот же результат для python3
$ python3 ./print_attributes.py [class attributes] b = 34 a = 12 [instance attributes] c = 4 d = 2
есть очень простой ответ, это должно быть очевидно: getattr
class MyClass(object): a = '12' b = '34' def myfunc(self): return self.a >>> getattr(MyClass, 'a') '12' >>> getattr(MyClass, 'myfunc') <function MyClass.myfunc at 0x10de45378>Он работает превосходно как в Python 2.7 и Python 3.x.
Если вам нужен список этих элементов, вам все равно нужно будет использовать inspect.
можно использовать
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('_')]
Это можно сделать без проверки, я думаю.
Возьмите следующий класс:
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, преобразуйте итераторы в списки.
если вы хотите более надежный способ сделать это, использовать проверить.
две функции:
def get_class_attr(Cls) -> []: import re return [a for a, v in Cls.__dict__.items() if not re.match('<function.*?>', str(v)) and not (a.startswith('__') and a.endswith('__'))] def get_class_attr_val(cls): attr = get_class_attr(type(cls)) attr_dict = {} for a in attr: attr_dict[a] = getattr(cls, a) return attr_dictиспользование:
>>> class MyClass: a = "12" b = "34" def myfunc(self): return self.a >>> m = MyClass() >>> get_class_attr_val(m) {'a': '12', 'b': '34'}
Я знаю, что это было три года назад, но для тех, кто придет к этому вопросу в будущем, для меня:
class_name.attributeработает просто отлично.
Comments