2012-11-28 54 views
14

我已经和与特殊属性,可以在三种不同的方式来命名对象(注:我不控制它生成对象的代码)越来越动态属性在Python

的(取决于哪一个设置)中的属性值是完全一样的,我需要得到进一步的处理,所以要根据数据的来源,我可以有这样的:

>>> 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%相信我做了什么:)提前

感谢

+0

只是为了检查 - 没有一个'get_value()'(或类似的),或者你提到'取决于数据源' - 没有现有的(或可导出的映射)源 - >属性名称? –

回答

28

如何:

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

我实际上试图避免尝试/除了在这一个..我应该已经提到,:) – rhormaza

+1

尝试/除了是典型的pythonic方式,你想避免它的任何好理由? – wim

+0

没有任何真正的理由,只是想保持代码简洁,我觉得一个尝试/除了有点太多:)我现在检查的另一件事是,该块不提供默认值的情况下没有这些属性存在,虽然这是非常不可能的,但我认为使用防御方法总是很好:) – rhormaza

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 
>>> 
+0

感谢这个,我完全错过了dir()...现在只是想知道...如何dir()调用内部工作。我会检查 – rhormaza

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) 

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

+1

我几乎发布了一些这样的效果。问题在于你最终会对你想要的元素进行两次检查(一次用'hasattr',一次用'getattr')。最终,我认为它并不比wim发布的显式循环更好 - 尽管我很乐于听到这个循环可能带来的优势。 – mgilson

+0

我猜可以使用嵌套的生成器来避免双向查找,但只有当它找到属性时才会发生,所以我认为它是一个小缺陷。不过,我刚刚添加了这样一个版本。 – kindall

+0

不错的一个...我要去看看..感谢 – rhormaza

0

根据您的对象的结构,可能有更好的方法来做到这一点,但除此之外别无所知,下面是一个递归解决方案,其工作方式与您当前的解决方案完全相同,只是它可以使用任意数量的参数:

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

我真的很喜欢这个,为简单和简洁 – rhormaza

-1

而另一个问题:

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

(在Python 3,你必须导入从functools减少。这是一个内置的Python 2)

+0

这假设'bool(obj.b)'是真的。考虑一下如果你有'obj.a = 0'会发生什么。我认为你不会选那个。 – mgilson