在 C# 中,我们可以通过反射来实现。在 JavaScript 中,它很简单:
for(var propertyName in objectName)
var currentPropertyValue = objectName[propertyName];
如何用Python实现此操作?
在 C# 中,我们可以通过反射来实现。在 JavaScript 中,它很简单:
for(var propertyName in objectName)
var currentPropertyValue = objectName[propertyName];
如何用Python实现此操作?
for property, value in vars(theObject).items():
print(property, ":", value)
请注意,在一些罕见情况下存在__slots__
属性,这种类通常没有__dict__
。
__setattr__()
。直接在字典上设置值会绕过对象的setter(和/或其父级) 。在python中,属性设置时背后可能发生更多的事情(例如数据清理),使用setattr()
可以确保您不会错过它们,或被迫自己明确处理它们。 - Michael Ekoka__dict__
注册的对象属性和方法)。它不会返回动态成员(即由该对象的__getattr__()
方法或类似魔术方法动态定义的对象属性和方法)。很可能你期望的file.ImplementationName
属性是动态定义的,因此在vars()
或dir()
中 _不可用_。 - Cecil Currydir()
是简单的方法。请参阅此处:
dir()
,谢谢。 - Abhishek Dujari请查看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']
>>>
inspect.getmembers()
是将dir()
进行了包装,(A)主要包括动态类属性和元类属性,这些相对较小的优点。 (B)它排除了不符合传递的谓词的成员。然而,对于标准用例来说,使用dir()
就足够了。inspect.getmembers()
适用于通用的第三方库,支持所有可能的对象类型。 - Cecil Curry__dict__
属性是对象的一个字典,包含了所有定义在该对象中的属性。需要注意的是,Python 类可以覆盖 getattr 并创建看起来像属性但不在__dict__
中的属性。此外还有内置函数 vars()
和 dir()
,它们在细节上有所不同。在一些特殊的类中,__slots__
可以替代__dict__
。
在 Python 中,对象很复杂。如果需要进行反射式编程,则应该从 __dict__
开始。如果你在交互式 shell 中进行编程,则应该从 dir()
开始。
对于一行代码:
print vars(theObject)
如果您正在寻找所有属性的反映,则上面的答案非常好。
如果您只是想获取字典的键(在Python中与“对象”不同),请使用
my_dict.keys()
my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys()
> ['abc', 'def', 'ghi']
obj['key']
vs. obj.property
),而问题是关于对象属性的。我在这里放置了我的答案,因为两者之间很容易混淆。 - MrE虽然其他回答已经完全覆盖了这一点,但我会明确表达一下。 一个对象可能有类属性和静态和动态实例属性。
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}
如果它是一种方法,它就会崩溃。
太长不看。尝试调用extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}
,但不包括方法和魔法。
我认为展示所提到的各种选项之间的区别是值得的 - 通常一幅图像胜过千言万语。
>>> 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__
-如果存在,它是明确放置在那里以进行查询的,并且应直接使用。我也没有涉及到元类,这可能会有点复杂(大多数人都不会使用它们)。
@property
修饰的类成员。 - Tomasz Gandor