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


133

IC#我们通过反思来做到。在Javascript中,它很简单:

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

如何在Python中完成?



3
请注意,这个问题用词不当。大多数答案是关于枚举成员。我正在寻找一种枚举属性的方法,即用修饰的类的成员@property
Tomasz Gandor

Answers:


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

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


1
现在如何更改值?在Javascript中,您可以执行以下操作:object [property] = newValue。如何在Python中完成?
贾德·迪亚斯

39
使用setattr()代替。
尼尔森2009年

1
@Nelson您能详细说明为什么这是一个更好的选择吗?它只是更短,还是有其他考虑?
WhyNotHugo 2014年

8
@Hugo:首先是因为它是“ pythonic”的,换句话说,这是大多数社区期望看到的语法。其他语法可能会不必要地使任何阅读您代码的人暂停。其次,某些类型实现了setter __setattr__()。直接在字典上设置值会绕过对象的设置器(和/或其父代)。在python中,在属性设置期间(例如卫生),在后台发生的事情多于视线,这是很常见的,使用setattr()确保您不会错过,或被迫自己明确地处理它们。
Michael Ekoka 2014年

3
@ Hi-Angel 确实有效。但是,什么是行不通的,却是先入为主的概念和假设的星座,而这些概念和假设与Python中的动态对象成员相比具有周围的状态。vars()仅返回静态成员(即,对象属性和在该对象的中注册的方法__dict__)。它并不能返回动态成员(由该对象的动态定义即,对象属性和方法__getattr__()的方法或类似的魔法)。您的期望file.ImplementationName属性极有可能是动态定义的,因此对或不可用。vars()dir()
Cecil Curry

69

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

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

>>> [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']
>>> 

是的,这个答案很好。以前从未使用过此模块。通过仅遍历dir(object),btw的结果来实现getmembers()。
尼尔森2009年

您能否详细说明为什么这比访问字典更好?Python文档并没有多大用处,特别是因为通常它使用attributes而不是members(这两者之间有任何区别吗?)。他们可以在Python 3.0中修复该名称,以使其一致。
nikow,2009年

抱歉__dict__,抱歉。
尼科夫

4
@nikow:即使内部详细信息发生更改,也可以保证inspect.getmembers()继续工作。
格奥尔格·舍利(GeorgSchölly)

3
@NicholasKnight inspect.getmembers()涡卷dir()与所述(主要是可忽略的)侧的好处(A) ,包括动态类属性元类的属性(B)不含成员匹配所传递的谓词。打哈欠吧? inspect.getmembers()适用于一般支持所有可能的对象类型的第三方库。但是,对于标准用例来说,dir()绝对足够。
Cecil Curry

66

dir()是简单的方法。看这里:

Python自省指南


2
Python文档中有一些要注意的地方,因为dir()主要是为了方便在交互式提示符下使用而提供的,所以它尝试提供一组有趣的名称,而不是尝试提供一组严格或一致定义的名称,并且其详细的行为可能会在各个发行版中发生变化。例如,当参数为类时,元类属性不在结果列表中。
skyler 2015年

1
在cli上执行草稿工作时,此答案是最好的。

15年的python(从来没有全职工作),我仍然忘记了dir()谢谢。
Abhishek Dujari

14

__dict__对象的属性是其所有其他定义的属性的字典。请注意,Python类可以覆盖getattr 并使内容看起来像属性,而不是in __dict__。还有一些内置函数vars()dir()它们在微妙的方式上有所不同。并且__slots__可以代替__dict__一些不寻常的类。

Python中的对象很复杂。__dict__是开始进行反射式编程的正确位置。dir()如果您是在交互式shell中四处乱逛,那么这是一个开始的地方。


print vars.__doc__表明With an argument, equivalent to object.__dict__那么细微的差别是什么?
sancho.s ReinstateMonicaCellio 2014年


10

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

如果您只是想获取字典的键(与Python中的“对象”不同),请使用

my_dict.keys()

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

1
即使是我的答案,我也不认为这应该是公认的答案:对象的键与类的对象实例的属性不同。对它们的访问方式有所不同(obj['key']vs. obj.property),问题在于对象属性。我将答案放在这里是因为两者之间容易混淆。
MrE

我实际上建议删除此答案。
Ente

如上所述,例如,来自Javascript或C#的人容易被术语混淆,因为这两个概念之间没有区别。人们学习python并尝试访问键很可能会搜索“属性”并最终出现在这里,因此我认为它属于其中。
MrE

并且您是对的,但是没有指出重点:在其他语言中(例如JS),对象和字典之间没有区别。OP来自C#,询问问题。这个答案虽然错了,但得到了11次投票,证明即使在严格的python术语上看这个问题时,从技术上讲,这并不是一个正确的答案(正如我指出的那样),这证明了落在这里的人们感到有用。我将进行编辑以使其更加清晰。
MrE

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'}这三个方法,但不要调用方法或魔术。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.