2011-09-26 101 views
1
檢查對象的類型

說我有一個名爲標籤的對象,我有三個類型的標籤通過以下方式實例變量指出,字符串與枚舉在Python中

class Tag(object): 
    def __init__(self, name, type): 
     self.name = name 
     self.type = type 

t1 = Tag("blue", "cold") 
t2 = Tag("red", "warm") 
t3 = Tag("black", "hot") 

比方說,我只允許三種類型:冷,熱和熱。最好去檢查它是否是這種類型之一?

if t1.type == "cold": 
    # do something 
elif t1.type == "warm": 
    # do something else 
else t1.type == "hot": 
    # do something even elser 

或者我應該創建一個枚舉類的物體,像從這個question之一,

class Type: 
    COLD=1 
    WARM=2   
    HOT=3 

,而是創建這樣的標籤?

t1 = Tag("blue", Type.COLD) 

我之所以問這個問題,是因爲我聽到了很多的處理能力,進入比較字符串,即使這些短短的3,4信長的話,很可能我會做幾數以千計的這些類型的比較。你認爲它值得去創建枚舉對象來確定一個對象的類型,就像我在上面顯示的例子那樣?還是有更好的方法來做我想做的事情?

+2

我認爲您列舉的解決方案的一個優點是它明確了允許的值是什麼。如果你接受任意字符串,我會認爲'更容易犯錯誤,更難記錄你的詞彙。例如,'logging'模塊使用這種解決方案來記錄日誌級別(例如'logging.DEBUG','logging.INFO'等等)。 – larsks

回答

0

在python中,使用字典進行調度比使用if/elif/else的塔更經常是有利的。

所以:

class Tag(object): 
    def __init__(self, name, type): 
     self.name = name 
     self.type = type 
     self.dispatch = {"cold":Tag.process_cold, "warm":Tag.process_warm, "hot":Tag.process_hot} 

    def process(self): 
     self.dispatch[type](self) 

    def process_cold(self): 
     # do something 

    def process_warm(self): 
     # do something else 

    def process_hot(self): 
     # do something even elser 

和代碼一小筆額外位可以自動建立調度表:

def dispatchTable(klass, prefix): 
    """ 
    Given a class and a method prefix string, collect all methods in the class 
    that start with the prefix, and return a dict mapping from the part of the 
    method name after the prefix to the method itself. 

    e.g. you have a class Machine with methods opcode_foo, opcode_bar. 
    create_dispatch_table(Machine, "opcode_") 
    yields a dict 
    { "foo": Machine.opcode_foo, "bar": Machine.opcode_bar } 
    """ 

    dispatch = {} 
    for name, fun in inspect.getmembers(klass, inspect.ismethod): 
     if name.startswith(prefix): 
      # print "found %s.%s"%(k.__name__,name) 
      dispatch[ name.split(prefix)[1] ] = fun 

    return dispatch 
2

性能差異可能不足以讓您擔心。如果你關心性能,你應該做一個簡單的測試。使用Python的timeit模塊來測試這兩種情況的性能。

2

我不會擔心這種表現,除非分析表明它確實是一個問題。如果您使用的是IDE,則枚舉方法具有錯字檢查功能。

+0

是的---錯字檢查和指定允許的值在這裏很重要,可能不是性能。 – JasonFruit

1

我會去相結合的方式 - 有「枚舉」是部分Tag類的接受一個字符串進行初始化,然後將其轉換。另外,不要使用一堆if/else分支,你可以使用一個字典來創建一個分派表。

class Tag(object): 
    COLD = 0 
    WARM = 1 
    HOT = 2 
    def __init__(self, name, temp): 
     if temp.upper() not in ('COLD', 'WARM', 'HOT'): 
      raise ValueError("Invalid temp: %r" % temp) 
     self.temp = getattr(self, temp.upper()) 
     self.name = name 
    def process(self): 
     func = self.temp_dispatch[self.temp] 
     func(self) # NOTE: have to pass 'self' explicitly 
    def cold(self): 
     print('brrr') 
    def warm(self): 
     print('ahhh') 
    def hot(self): 
     print('ouch!') 
    temp_dispatch = {COLD:cold, WARM:warm, HOT:hot} 

tag = Tag('testing', 'Cold') 
tag.process()