2016-02-11 48 views
3

假设我有其生成调用取决于数是否为奇数或偶数指定回调路由器功能的功能:重新使用一个全局函数

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

我也有类装饰该附加一个类似路由器的方法,命名为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()和​​:

​​

如果我想重新使用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()变称为,生成一个新的(但相同的)路由器功能。因此,这里是我的问题:我怎么能重复使用odd_even_router()发生器内attach_default_router()装饰,但没有产生的每一次新的路由器的功能?

问题在心脏是:odd_even_router()返回一个函数,它有一个参数,但check_number(),是一个实例方法,需要两个(第一个是对象的self)。如果我没有得到self,我还无法生成路由器功能。当我得到self时,我已经在方法中,并且在那里生成它需要在每次调用方法时生成。

我怎么能解决这个难题呢?

+0

你有没有考虑过使用的混入,而不是类装饰? –

+0

感谢您向我介绍术语“mixin”。看完以后,我会说这只是多重继承。那么,我确实考虑过多重继承,但我有一个(有点不合理的)逆境。在我的情况下,要装饰的类是所有其他类的扩展,所以我的直觉是避免从一个以上的东西继承。但是,是的,这是一个选择。我会牢记这一点。 –

回答

2

你可以,但是你必须在运行时绑定你的oddeven钩子,这需要你的工厂稍微不同的实现。

这是因为不仅是你的route功能的全新每次产生的,所以*是oddeven方法。 self.odd创建每次执行一个表达时间的新方法的包装,因为functions are descriptors,并正在绑定到实例(self这里)每次需要时间。

所以,如果你想生成与装饰类的所有实例使用一个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()工厂函数。

+0

提醒一下:您忘记了工厂功能中的“返回路线”。谢谢。我想,就像大多数工程问题一样,没有“完美”的解决方案,只有折衷。 –

+0

糟糕,添加了返回语句。确实;尽管使用Python进行工程设计对我来说感觉更加有趣:-) –