2010-02-28 25 views
2

我目前做這個,做的基於對象的類型不同的東西:按類名切換python?

actions = { 
     SomeClass: lambda: obj.name 
     AnotherClass: lambda: self.normalize(obj.identifier) 
     ...[5 more of these]... 
    } 

    for a in actions.keys(): 
     if isinstance(obj, a): 
      return actions[a]() 

是否有可能切出的for循環,而做這樣的事情?

actions[something to do with obj]() 
+7

請不要。這是實現多態的可怕方式。 – 2010-02-28 15:43:48

回答

0

什麼

actions[obj.__class__]() 
0
actions[type(obj)]() 
1
actions[obj.__class__]() 

作品如果obj是真的的一個子類(比方說)SomeClass,而不是一個實例 - 所以如果可以的情況下,結果將與您目前的處理方式不同。另請注意,如果該類沒有相應的操作,則可能會引起KeyError。爲了處理這種情況下,你現在做同樣的方式(即什麼都不做),你可以使用

有一個默認值返回。

哦,聽你的問題美國洛特的評論。在很多情況下,有更好的方法來實現這樣的事情。例如,您可以讓所有課程定義一個do_whatever(self),並且只需撥打obj.do_whatever()即可。

0
results = [func() for cls, func in actions.iteritems() if isinstance(obj, cls)] 

如果您的對象爲isinstance爲零個或多個class-keys,則會有零個或多個結果。

使用type(obj)關鍵,如果你的對象是一個類型的纔有效。如果它繼承樹的下面,你會錯過它。

6
class SomeClass(object): 
.... 
    def action(self): 
     return self.name 

class AnotherClass(object): 
.... 
    def action(self): 
     return self.normalize(self.identifier) 

[5 more classes like the above two] 

a.action() 

更簡單。清晰。更具可擴展性。魔術減少。沒有字典。沒有循環。

+0

+1。任何暗示「行動」依賴於*兩個*對象('類)的情況?這是我在當前項目中遇到的一個問題,我還沒有想到比'isinstance'測試更好的方法。 – balpha 2010-02-28 15:55:24

+0

@balpha:他們稱之爲「雙派」。這是相同的基本演習,除了類層次結構A從另一個類中選擇一個方法。一是研究「雙派」。然後問一個單獨的問題,如果你仍然有麻煩。 – 2010-02-28 16:07:20

+0

我認爲真正的問題是如何組織Python代碼,以便所有的「動作」方法彼此接近,而不是在每個類中植入一個。在Scala中,匹配{}構造可以讓你做到這一點,如果你有一個不匹配的類型,甚至會拋出編譯時類型錯誤,所以它似乎是一種可接受的佈局多態代碼的方式。 – codewarrior 2011-07-04 00:12:34

1

我假設你擁有所有這些的父類,或至少一個mixin。把一個默認的返回函數放在父類或mixin中,然後在不同的類中重載它......這是唯一正確的方法。

當然,它使額外的代碼,但至少它的封裝和可擴展性。假設你想增加對另外五個班級的支持。不要在那裏修改代碼,只需將正確的代碼添加到新類中即可。從外觀上看,每班有兩條線(功能定義和返回線)。這並不壞,是嗎?

如果obj不包含返回功能,那麼將引發異常,你能趕上並用​​乾淨的良心忽視的一類。

class MyMixin: 
    def my_return(self, *args): 
    return self.name 
    ... possibly other things... 

class SomeClass(MyMixin): 
    ... no alteration to the default ... 

class AnotherClass(MyParent, MyMixin): 
    def my_return(self, *args): 
    return args[0].normalize(self.identifier) 
    ... blabla 


# now, this is in the caller object... 
try: 
    rval = obj.my_return(self) # this is the caller object 'self', not the 'self' in the 'obj' 
    #dosomething with rval 
except Exception: 
    pass #no rval for this object type, skipping it... 
+0

用Python的鴨子打字,mixin不是必須的。只要所有類都使用正確的參數集來實現'my_return',它應該可以正常工作。然而,Tor是正確的,擁有一個共同的父類是有幫助的,因爲它允許你提供一個默認行爲,除非另有說明,否則你的所有類都將遵循。 – jcdyer 2010-02-28 16:32:30

+0

這是我所做的假設,特定類之間存在某種關係。 – 2010-02-28 17:16:47