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

Jad*_*ias 116 python reflection properties

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

for(var propertyName in objectName)
    var currentPropertyValue = objectName[propertyName];
Run Code Online (Sandbox Code Playgroud)

怎么用Python做?

Geo*_*lly 136

for property, value in vars(theObject).iteritems():
    print property, ": ", value
Run Code Online (Sandbox Code Playgroud)

请注意,在一些罕见的情况下,有一个__slots__属性,这类通常没有__dict__.

  • 请改用setattr(). (35认同)
  • @Hugo:首先是因为它是"pythonic",换句话说,这是大多数社区期望看到的语法.另一种语法可能会不必要地让任何读取代码的人暂停.其次,一些类型实现了一个setter`__setattr __()`.直接在字典上设置值会绕过对象的setter(和/或其父项).它在Python里是相当常见的比满足眼睛更加事情()发生在属性设定(如卫生)期间的背景下,使用``的setattr确保您不会错过,或被迫明确地处理它们自己. (7认同)
  • @Hi-Angel _确实_有效。然而,不起作用的是您对 Python 中的状态与动态对象成员的先入之见和假设的组合。`vars()` 只返回 **static 成员**(即使用该对象的 `__dict__` 注册的对象属性和方法)。它确实_不_返回**动态成员**(即,由该对象的`__getattr__()` 方法或类似魔法动态定义的对象属性和方法)。很可能,你想要的 `file.ImplementationName` 属性是动态定义的,因此 _not_ 可用于 `vars()` 或 `dir()`。 (3认同)
  • @CecilCurry 伙计,虽然我很欣赏你的启发性评论,但我不欣赏你的讽刺。你刚才说的不是显而易见的,也不是很容易找到,除非你对语言内部有足够的了解而不会在这里问。应该在答案中提到它。 (2认同)

gim*_*mel 66

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']
>>> 
Run Code Online (Sandbox Code Playgroud)

  • @nikow:inspect.getmembers()保证即使内部细节发生变化也能继续工作. (4认同)
  • @NicholasKnight`inspection.getmembers()`包装`dir()`用**(A)**的(大多数可以忽略的)附带好处,包括[动态类属性](https://docs.python.org/3/ library/types.html#types.DynamicClassAttribute)和[metaclass attributes](http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python)和**(B)**不包括成员_not_匹配传递的谓词._Yawn,对吗?_` inspect.getmembers()`适用于通常支持所有可能对象类型的第三方库.但是,对于标准用例,`dir()`绝对足够. (3认同)

EBG*_*een 55

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

Python内省指南

  • 从 Python 文档中需要注意的一点是,_because dir() 主要是为了在交互式提示下方便使用而提供的,它试图提供一组有趣的名称,而不是尝试提供一组严格或一致定义的名称,并且它的详细行为可能会随着版本的不同而改变。例如,当参数是类时,元类属性不在结果列表中。_ (4认同)

Nel*_*son 12

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

Python中的对象很复杂.__dict__是反思式编程的正确起点.dir()如果你在一个交互式shell中乱砍,那就是开始的地方.


Nic*_*ojo 11

georg scholly较短的版本

print vars(theObject)
Run Code Online (Sandbox Code Playgroud)


MrE*_*MrE 11

如果您正在寻找所有属性的反映,上面的答案都很棒.

如果您只是想获取对象的键,请使用

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']
Run Code Online (Sandbox Code Playgroud)

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

Mat*_*rla 5

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

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

    def fx(self):
        return 3
Run Code Online (Sandbox Code Playgroud)

stasis是静态的,dyno是动态的(参见属性装饰器)并且classy是一个类属性。如果我们只是这样做,__dict__或者vars我们只会得到静态的。

o = foo()
print(o.__dict__) #{'stasis': 2}
print(vars(o)) #{'stasis': 2}
Run Code Online (Sandbox Code Playgroud)

所以如果我们想要其他人__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}
Run Code Online (Sandbox Code Playgroud)

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

import json
print(json.dumps(d)) #{"stasis": 2, "classy": 1, "dyno": 1}
Run Code Online (Sandbox Code Playgroud)

如果它是一种方法,它就会崩溃。

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