遍历一个对象的“公共”属性

17

最近,我发现自己写出了这样的代码:

for name in dir( object ):
    if name.startswith( '__' ) : continue
    ...

有没有更符合python风格的方法来访问对象的“公共”命名空间?


2
你首先要解决什么问题,这个结构才有用呢? - SingleNegationElimination
那么 for name in filter( lambda x: not x.startswith('_'), dir(obj)): 怎么样?请注意,在Python中,即使是一个下划线 (_) 也意味着它是一个 "私有" 属性。 - Niklas R
2
@NiklasR for name in ( x for x in dir(obj) if not x.startswith('_') ): 不需要过滤器。 - Dan D.
有趣的是,这个问题被标记为一个6个月后才被问到的问题的重复。 - William Pursell
1
这也很奇怪,问题提出已经5年了! - William Pursell
3个回答

22
你可以使用 vars 函数
例如:
>>> class C(object):
...   def __init__(self):
...     self.__foo = 'foo'
... 
>>> c = C()
>>> dir(c)
['_C__foo', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__',    
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',    
'__weakref__']
>>> vars(c)
{'_C__foo': 'foo'}
请注意,正如 Niklas R 指出的那样,具有单个下划线的变量也被视为私有变量。但是,vars() 函数的优点在于消除了除实例变量以外的所有变量。

2
当我在一些其他对象上尝试这个时,会出现“TypeError: vars() argument must have dict attribute”的错误。 - wim
3
是的,vars()函数只能用于具有__dict__属性的对象。因此,例如,如果在您的类上定义了__slots__,则无法使用vars()函数。 - srgerg
2
请注意,这不会获取任何属性,因此不仅有 __slots__ 的东西不起作用。 - Joe Kington

19
你可以在之前准备一个“公共”属性列表(作为列表或生成器):
>>> public_props = (name for name in dir(object) if not name.startswith('_'))
>>> for name in public_props:
    print name

但请注意文档中关于dir()函数的说明:

注意 因为dir()主要是作为交互式提示使用的便利,它试图提供一组有趣的名称而不是严格或一致定义的名称集,并且其详细行为可能会在发布版本之间更改。例如,当参数为类时,元类属性不在结果列表中。

您还应该知道,任何类都可以实现__dir__()方法,该方法可能返回不一定对应于属性名称的名称列表。换句话说,dir(something)不能保证结果将返回something的属性。


1
有什么理由更喜欢使用dir(object)而不是object.__dict__吗? - Dave
1
object.__dict__并不一定返回您想要的属性,至少根据我的测试结果是这样的。 - James Lin

2
与其使用 continue 关键字来进行排除操作,直接迭代公共名称的推导式似乎更符合 Python 风格。但这可能只是个人口味问题,承认它并不比你已经拥有的方法好多少。
public_names = (n for n in dir(object) if not n.startswith('_'))
for attr in public_names:
    ...

注意: 单下划线属性也不是“公共的”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接