关于getattr:在python中获取动态属性

getting dynamic attribute in python

本问题已经有最佳答案,请猛点这里访问。

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

属性中的值(取决于设置了哪一个)完全相同,我需要获取该值进行进一步处理,因此根据数据源,我可以具有如下内容:

1
2
3
4
5
6
7
8
9
10
>>> 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'

1
2
3
4
5
6
7
8
9
10
>>> 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'

1
2
3
4
5
6
7
8
9
10
>>> 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电话。假设可能性只有三个,代码如下所示:

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

现在,我想知道有没有更好的方法?因为我100%确信我所做的一切:)

提前谢谢


怎么样:

1
2
3
4
5
6
7
for name in 'a', 'b', 'c':
    try:
        thing = getattr(obj, name)
    except AttributeError:
        pass
    else:
        break


这有助于处理任意数量的项目:

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

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

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

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


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

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


我认为使用dir基本上可以得到和__dict__一样的结果。

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

有点像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> 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
>>>


另一个是:

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

(在python 3中,必须从functools导入reduce。它是Python2中内置的)