在python中获取动态属性

时间:2012-11-28 00:23:49

标签: python getattr

我有一个特殊属性,可以用三种不同的方式命名(注意:我不控制生成对象的代码)

属性中的值(取决于哪一个设置)完全相同,我需要进行进一步处理,因此根据数据来源,我可以得到类似的内容:

>>> obj.a
'value'
>>> obj.b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Obj instance has no attribute 'b'
>>> obj.c
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Obj instance has no attribute 'c'

>>> obj.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Obj instance has no attribute 'a'
>>> obj.b
'value'
>>> obj.c
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Obj instance has no attribute 'c'

>>> obj.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Obj instance has no attribute 'a'
>>> obj.b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Obj instance has no attribute 'b'
 >>> obj.c
'value'

我对获取'value'感兴趣,遗憾的是__dict__属性在该对象中不存在。所以我最终为获得该值而做的只是做了一堆getattr次调用。假设可能性只有三个,代码看起来像这样:

>>> g = lambda o, l: getattr(o, l[0], getattr(o, l[1], getattr(o, l[2], None)))
>>> g(obj, ('a', 'b', 'c'))
'value'

现在,我想知道是否有更好的方法呢?因为我100%确信我做了什么:)

提前致谢

5 个答案:

答案 0 :(得分:38)

怎么样:

for name in 'a', 'b', 'c':
    try:
        thing = getattr(obj, name)
    except AttributeError:
        pass
    else:
        break

答案 1 :(得分:2)

这样做的好处是可以使用任意数量的项目:

 def getfirstattr(obj, *attrs):
     return next((getattr(obj, attr) for attr in attrs 
                  if hasattr(obj, attr)), None)

这确实有非常次要的缺点,即它对最终值进行两次查找:一次检查属性是否存在,另一次实际获取值。使用嵌套的生成器表达式可以避免这种情况:

 def getfirstattr(obj, *attrs):
     return next((val for val in (getattr(obj, attr, None) for attr in attrs)
                  if val is not None), None)

但我觉得这不是什么大不了的事。即使使用双重查找,生成器表达式也可能比普通的旧循环更快。

答案 2 :(得分:0)

我认为使用dir会让你__dict__通常做同样的事情......

targetValue = "value"
for k in dir(obj):
    if getattr(obj,k) == targetValue:
       print "%s=%s"%(k,targetValue)

类似

>>> class x:
...    a = "value"
...
>>> dir(x)
['__doc__', '__module__', 'a']
>>> X = x()
>>> dir(X)
['__doc__', '__module__', 'a']
>>> for k in dir(X):
...     if getattr(X,k) == "value":
...        print "%s=%s"%(k,getattr(X,k))
...
a=value
>>>

答案 3 :(得分:0)

根据对象的结构,可能有更好的方法,但不知道其他什么,这里是一个递归解决方案,其工作方式与当前解决方案完全相同,只不过它可以使用任意数量的参数:< / p>

g = lambda o, l: getattr(o, l[0], g(o, l[1:])) if l else None

答案 4 :(得分:-1)

还有一个:

reduce(lambda x, y:x or  getattr(obj, y, None),  "a b c".split(), None)

(在Python 3中你必须从functools导入reduce。它是Python 2内置的)