簡體   English   中英

在類裝飾器中重用全局函數

[英]Re-use a global function within a class decorator

假設我有一個生成路由器函數的函數,該函數根據數字是奇數還是偶數來調用指定的回調:

def odd_even_router(odd, even):
    def r(n):
        if n % 2:
            odd(n)
        else:
            even(n)
    return r

我還有一個類裝飾器,它將一個名為check_number的類似路由器方法check_number到一個類:

def attach_default_router(cls):
    def route(self, n):
        if n % 2:
            self.on_odd(n)
        else:
            self.on_even(n)

    cls.check_number = route
    return cls

然后,用@attach_default_router修飾的類自動定義了check_number() ,只需要實現on_odd()on_even()

@attach_default_router
class A(object):
    def on_odd(self, n):
        print 'Odd number'

    def on_even(self, n):
        print 'Even number'

如果我想重新使用odd_even_router() ,路由器函數生成器,在attach_default_router() ,我可以這樣做:

def attach_default_router(cls):
    def route(self, n):
        r = odd_even_router(self.on_odd, self.on_even)
        r(n)

    cls.check_number = route
    return cls

然而,不期望的效果是,每次調用check_number()時,都會生成新的(但相同的)路由器功能。 所以這是我的問題: 如何在attach_default_router()裝飾器中重新使用odd_even_router()生成器,但attach_default_router()生成新的路由器函數?

問題的核心是: odd_even_router()返回一個接受一個參數的函數,但check_number()是一個實例方法,需要兩個(第一個是對象的self )。 如果我沒有掌握self ,我還無法生成路由器功能。 當我抓住self ,我已經在方法中,並且在那里生成它需要在每次調用方法時生成。

我怎么能解決這個難題?

你可以,但是你必須在運行時綁定你的oddeven鈎子,需要稍微不同的工廠實現。

這是因為你的route功能不僅每次產生一個新的,* oddeven方法也是even 每次執行該表達式時, self.odd都會創建一個新的方法包裝器,因為函數是描述符 ,並且每次需要時都綁定到實例( self here)。

因此,如果要生成一個 route()函數以用於裝飾類的所有實例,則必須手動確保綁定仍然發生:

def odd_even_router_method_factory(odd, even):
    def route(self, n):
        if n % 2:
            odd.__get__(self)(n)
        else:
            even.__get__(self)(n)
    return route

def attach_default_router(cls):
    route = odd_even_router_method_factory(cls.on_odd, cls.on_even)
    cls.check_number = route
    return cls

請注意,Python現在仍將創建一個route方法對象 每次訪問instance_of_your_decorated_class.route ,都會通過描述符協議創建方法對象。 當調用odd.__get__() even.__get__()發生同樣的情況。 你也可以堅持你的原始版本,並為每個調用生成一個新的route()函數,傳入self.oddself.even ,因為它可能更具可讀性,並保持你原來的odd_even_router()工廠函數可以使用作為方法和功能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM