2012-11-28 79 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