如何在Python中枚举对象的属性?

时间:2009-08-09 16:33:03

标签: python reflection properties

我是C#我们通过反思来做到这一点。在Javascript中它很简单:

for(var propertyName in objectName)
    var currentPropertyValue = objectName[propertyName];

如何在Python中完成?

8 个答案:

答案 0 :(得分:124)

for property, value in vars(theObject).iteritems():
    print property, ": ", value

请注意,在极少数情况下会有__slots__属性,此类通常没有__dict__

答案 1 :(得分:64)

请参阅inspect.getmembers(object[, predicate])

  

返回按名称排序的(名称,值)对列表中对象的所有成员。如果提供了可选的谓词参数,则仅包含谓词返回true值的成员。

>>> [name for name,thing in inspect.getmembers([])]
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', 
'__delslice__',    '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', 
'__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', 
'__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__','__reduce_ex__', 
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', 
'__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 
'insert', 'pop', 'remove', 'reverse', 'sort']
>>> 

答案 2 :(得分:50)

dir()是一种简单的方法。见这里:

Guide To Python Introspection

答案 3 :(得分:12)

对象的__dict__属性是其所有其他已定义属性的字典。请注意,Python类可以覆盖getattr 并使事物看起来像属性但不在__dict__。还有内置函数vars()dir(),这些函数在细微方面有所不同。 __slots__可以在某些不常见的类中替换__dict__

Python中的对象很复杂。 __dict__是反思式编程的正确起点。如果您在交互式shell中进行黑客攻击,dir()就是您的起点。

答案 4 :(得分:11)

georg scholly更短的版本

print vars(theObject)

答案 5 :(得分:9)

如果你正在寻找所有属性的反映,那么上面的答案都很棒。

如果您只想获取对象的密钥,请使用

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']

答案 6 :(得分:5)

其他答案完全涵盖了这一点,但我会明确指出。 一个对象可能具有类属性以及静态和动态实例属性。

class foo:
    classy = 1
    @property
    def dyno(self):
        return 1
    def __init__(self):
        self.stasis = 2

    def fx(self):
        return 3

stasis是静态的,dyno是动态的(参见属性装饰器),而classy是类属性。如果我们只做__dict__vars,我们只会得到静态的。

o = foo()
print(o.__dict__) #{'stasis': 2}
print(vars(o)) #{'stasis': 2}

因此,如果我们希望其他人__dict__将获得一切(甚至更多)。 这包括魔术方法和属性以及法线绑定方法。因此,请避免这些情况:

d = {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}
print(d) #{'stasis': 2, 'classy': 1, 'dyno': 1}

使用属性修饰方法(动态属性)调用的type将为您提供返回值的类型,而不是method。为了证明这一点,让我们用json将其字符串化:

import json
print(json.dumps(d)) #{"stasis": 2, "classy": 1, "dyno": 1}

如果这是一种可能会崩溃的方法。

TL; DR。尝试为所有这三个调用extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'},但不要调用方法或魔术。

答案 7 :(得分:1)

我认为值得一提的是,提到的各种选择之间的区别-通常一张图片值一千字。

>>> from pprint import pprint
>>> import inspect
>>>
>>> class a():
    x = 1               # static class member
    def __init__(self):
        self.y = 2      # static instance member
    @property
    def dyn_prop(self): # dynamic property
        print('DYNPROP WAS HERE')
        return 3
    def test(self):     # function member
        pass
    @classmethod
    def myclassmethod(cls): # class method; static methods behave the same
        pass

>>> i = a()
>>> pprint(i.__dict__)
{'y': 2}
>>> pprint(vars(i))
{'y': 2}
>>> pprint(dir(i))
['__class__',
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__le__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 'dyn_prop',
 'myclassmethod',
 'test',
 'x',
 'y']
>>> pprint(inspect.getmembers(i))
DYNPROP WAS HERE
[('__class__', <class '__main__.a'>),
 ('__delattr__',
  <method-wrapper '__delattr__' of a object at 0x000001CB891BC7F0>),
 ('__dict__', {'y': 2}),
 ('__dir__', <built-in method __dir__ of a object at 0x000001CB891BC7F0>),
 ('__doc__', None),
 ('__eq__', <method-wrapper '__eq__' of a object at 0x000001CB891BC7F0>),
 ('__format__', <built-in method __format__ of a object at 0x000001CB891BC7F0>),
 ('__ge__', <method-wrapper '__ge__' of a object at 0x000001CB891BC7F0>),
 ('__getattribute__',
  <method-wrapper '__getattribute__' of a object at 0x000001CB891BC7F0>),
 ('__gt__', <method-wrapper '__gt__' of a object at 0x000001CB891BC7F0>),
 ('__hash__', <method-wrapper '__hash__' of a object at 0x000001CB891BC7F0>),
 ('__init__',
  <bound method a.__init__ of <__main__.a object at 0x000001CB891BC7F0>>),
 ('__init_subclass__',
  <built-in method __init_subclass__ of type object at 0x000001CB87CA6A70>),
 ('__le__', <method-wrapper '__le__' of a object at 0x000001CB891BC7F0>),
 ('__lt__', <method-wrapper '__lt__' of a object at 0x000001CB891BC7F0>),
 ('__module__', '__main__'),
 ('__ne__', <method-wrapper '__ne__' of a object at 0x000001CB891BC7F0>),
 ('__new__', <built-in method __new__ of type object at 0x00007FFCA630AB50>),
 ('__reduce__', <built-in method __reduce__ of a object at 0x000001CB891BC7F0>),
 ('__reduce_ex__',
  <built-in method __reduce_ex__ of a object at 0x000001CB891BC7F0>),
 ('__repr__', <method-wrapper '__repr__' of a object at 0x000001CB891BC7F0>),
 ('__setattr__',
  <method-wrapper '__setattr__' of a object at 0x000001CB891BC7F0>),
 ('__sizeof__', <built-in method __sizeof__ of a object at 0x000001CB891BC7F0>),
 ('__str__', <method-wrapper '__str__' of a object at 0x000001CB891BC7F0>),
 ('__subclasshook__',
  <built-in method __subclasshook__ of type object at 0x000001CB87CA6A70>),
 ('__weakref__', None),
 ('dyn_prop', 3),
 ('myclassmethod', <bound method a.myclassmethod of <class '__main__.a'>>),
 ('test', <bound method a.test of <__main__.a object at 0x000001CB891BC7F0>>),
 ('x', 1),
 ('y', 2)]

总结:

  • vars()__dict__仅返回实例本地属性;
  • dir()返回所有内容,但仅作为字符串成员名称列表返回;动态属性不被调用;
  • inspect.getmembers()返回所有内容,作为元组列表(name, value);它实际上运行动态属性,并接受可选的predicate参数,该参数可以按值过滤成员

因此,除非有特殊的性能考虑,否则我的常识性方法通常是在命令行上使用dir(),在程序中使用getmembers()

请注意,为了使内容更整洁,我没有添加__slots__-如果存在,则明确地将其放置在{em> 中进行查询,应直接使用。我也没有介绍元类,因为元类会有点毛病(大多数人永远不会使用它们)。