26

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

属性中的值(取决于设置的值)完全相同,我需要获取它以进行进一步处理,因此根据数据源,我可以有类似的东西:

>>> 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% 相信我所做的 :)

提前致谢

4

5 回答 5

55

怎么样:

for name in 'a', 'b', 'c':
    try:
        thing = getattr(obj, name)
    except AttributeError:
        pass
    else:
        break
于 2012-11-28T00:30:28.153 回答
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)

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

于 2012-11-28T00:32:23.310 回答
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
>>>
于 2012-11-28T00:27:50.013 回答
0

根据您的对象的结构,可能有更好的方法来做到这一点,但不知道别的,这是一个递归解决方案,它与您当前的解决方案完全一样,除了它可以使用任意数量的参数:

g = lambda o, l: getattr(o, l[0], g(o, l[1:])) if l else None
于 2012-11-28T00:32:30.630 回答
-1

还有一个:

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

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

于 2012-11-28T00:45:58.793 回答