获取一个类的属性
我想获得一个类的属性,说:
class MyClass(): a = "12" b = "34" def myfunc(self): return self.a
使用MyClass.__dict__
给了我一个属性和函数的列表,甚至像__module__
和__doc__
这样的函数。 虽然MyClass().__dict__
给我一个空的字典,除非我明确设置该实例的属性值。
我只是想要的属性,在上面的例子是: a
和b
尝试检查模块。 getmembers
和各种testing应该是有帮助的。
编辑:
例如,
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')]
…其中更复杂的可以包括特殊的属性名称检查甚至元类;)
def props(cls): return [i for i in cls.__dict__.keys() if i[:1] != '_'] properties = props(MyClass)
myfunc
是 MyClass
一个属性。 这就是运行时发现的:
myinstance = MyClass() myinstance.myfunc()
它在myinstance
上查找一个名为myfunc
的属性,找不到它,看到myinstance
是MyClass
一个实例并在那里查找它。
所以MyClass
的完整属性列表是:
>>> dir(MyClass) ['__doc__', '__module__', 'a', 'b', 'myfunc']
(请注意,我正在使用dir作为列出类的成员的简单方法:只能以探索性方式使用,而不能用于生产代码)
如果你只想要特定的属性,你需要使用一些标准来过滤这个列表,因为__module__
, __module__
和myfunc
在任何方面都不是特殊的,它们的属性和b
和b
属性完全一样。
我从来没有使用Matt和Borealid提到的inspect模块,但是从一个简单的链接看起来它有testing来帮助你这样做,但是你需要编写你自己的谓词函数,因为它看起来是你想要的大致是那些不通过isroutine
testing的属性, 不能以两个下划线开始和结束。
另请注意:通过使用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__
然而,“正确的”是通过检查模块来做到这一点。
我的解决scheme来获得一个类的所有属性(而不是方法)
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
一个实例被创build,除了类属性之外没有任何属性或方法,因此空的__dict__
所以,如果你说print(MyClass().b)
,Python首先检查新实例的字典MyClass().__dict__['b']
并找不到b
。 然后检查类MyClass.__dict__['b']
并findb
。
这就是为什么您需要inspect
模块来模拟相同的search过程。
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
。 但是,如果dynamic地向mc
添加一个属性,例如mc.c = "42"
,则在此策略中使用type(mc)
时,该属性不会显示出来。 它只给出了原始类的属性。
为了获得一个类实例的完整字典,你需要结合type(mc).__dict__
和mc.__dict__
type(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()
。
但是静态方法 并不总是可以被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
我知道这是三年前的事,但对于未来这个问题的人来说,对我来说,
class_name.attribute
工作得很好。