如何在 Python 中枚举对象的属性?[重复]
- 2025-03-13 09:05:00
- admin 原创
- 68
问题描述:
IC# 我们通过反射来实现。在 Javascript 中很简单:
for(var propertyName in objectName)
var currentPropertyValue = objectName[propertyName];
如何用 Python 来实现?
解决方案 1:
for property, value in vars(theObject).items():
print(property, ":", value)
请注意,在某些罕见情况下存在__slots__
属性,此类通常没有__dict__
。
解决方案 2:
dir()
是简单的方法。请参见此处:
Python 自省指南
解决方案 3:
看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']
>>>
解决方案 4:
对象的属性__dict__
是其所有其他已定义属性的字典。请注意,Python 类可以覆盖getattr
并创建看起来像属性但不存在于 中的东西__dict__
。还有内置函数vars()
和 ,dir()
它们在细微方面有所不同。 和__slots__
可以在一些不寻常的类中替换__dict__
。
Python 中的对象很复杂。__dict__
是开始进行反射式编程的正确地方。dir()
如果您在交互式 shell 中进行破解,那么这里就是您的起点。
解决方案 5:
对于单行代码:
print vars(theObject)
解决方案 6:
如果您正在寻找所有属性的反射,上面的答案就很棒。
如果你只是想获取字典的键(与 Python 中的“对象”不同),请使用
my_dict.keys()
my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys()
> ['abc', 'def', 'ghi']
解决方案 7:
其他答案完全涵盖了这一点,但我会明确说明。一个对象可能具有类属性以及静态和动态实例属性。
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'}
所有这三个,但不是方法也不是魔法。
解决方案 8:
我认为值得展示一下上述各种选项之间的差异——通常一张图片胜过千言万语。
>>> 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__
- 如果存在,它被明确地放在那里以供查询,并且应该直接使用。我也没有介绍元类,这可能会有点棘手(大多数人无论如何都不会使用它们)。
扫码咨询,免费领取项目管理大礼包!