2012-08-10 46 views
1

我試圖做一個排序類型處理函數的註冊,使用此代碼:類級別的裝飾

types = {} 
def type_handler(name): 
    def wrapper(f): 
     types[name] = f 
     return f 
    return wrapper 

@type_handler('a') 
def handle_a(a): 
    ... 

@type_handler('b'): 
def handle_b(b): 
    ... 

def handle(x): 
    types[x.name](x) 

這工作得很好,但現在我想它一個類的內部工作。
我嘗試這樣做:

class MyClass(object): 

    types = {} 
    def type_handler(name): 
     def wrapper(f): 
      types[name] = f ## global name 'types' is undefined 
      return f 
     return wrapper 

    @type_handler('a') 
    def handle_a(self, a): 
     ... 

    @type_handler('b'): 
    def handle_b(self, b): 
     ... 

    def handle(self, x): 
     self.types[x.name](self, x) 

但它說global name 'types' is undefined
我試圖將其更改爲

def type_handler(name): 
     def wrapper(f): 
      MyClass.types[name] = f ## global name 'MyClass' is undefined 
      return f 
     return wrapper 

但現在說global name 'MyClass' is undefined
我能做些什麼來完成這項工作?

我知道我可以這樣做:

def handle(self, x): 
    self.__getattribute__('handle_%s' % x.name)(self, x) 

但我更喜歡功能定位而命名基於查找。

+0

@SvenMarnach:固定 – Dani 2012-08-10 10:33:52

+1

原因你的行爲看到的是在名稱查找過程中跳過了類作用域 - 請參閱[在塊類中定義的名稱範圍不會擴展到方法的塊。爲什麼這是?](http://stackoverflow.com/questions/9505979/the-scope-of-names-defined-in-class-block-doesnt-extend-to-the-methods-blocks)進一步的解釋。 – 2012-08-10 10:40:09

+1

有幾種方法可以解決這個問題,但是如果不知道這個裝飾器的上下文是什麼,我無法真正給出一個好的建議。我的一般建議是使用更少的魔法。 – 2012-08-10 10:41:20

回答

3

我同意Sven Marnach。你應該使用「少魔術」。然而,這裏是一個快速的解決辦法:

#decorator is declared outside of class and type dict is passed in as an argument 
def type_handler(name, type_dict): 
    def wrapper(f): 
     type_dict[name] = f 
     return f 
    return wrapper 

class MyClass(object): 

    types = {} 

    @type_handler('a', types) 
    def foo_a(self, a): 
     pass 

    @type_handler('b', types) 
    def foo_b(self, b): 
     pass 

VERSION 2

這其中使用了類作爲裝飾:

class TypeHandler(object): 
    def __init__(self, type_dict): 
     self.types = type_dict 

    def __call__(self, name): 
     def wrapper(f): 
      self.types[name] = f 
      return f 
     return wrapper 


class MyClass(object): 
    types = {} 
    thandle = TypeHandler(types) 

    @thandle('a') 
    def foo_a(self, a): 
     pass 
+0

這對裝飾器調用有點多餘。 – Dani 2012-08-10 11:07:27

+0

@Dani:見編輯。 – 2012-08-10 11:20:32