繁体   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