2012-02-24 60 views
2

我定义几个类拟用于多重继承,如:检测super()是否具有装饰器的功能?

class A: 
    def __init__(self, bacon = None, **kwargs): 
     self.bacon = bacon 
     if bacon is None: 
      self.bacon = 100 
     super().__init__(**kwargs) 
class Bacon(A): 
    def __init__(self, **kwargs): 
     """Optional: bacon""" 
     super().__init__(**kwargs) 

class Eggs(A): 
    def __init__(self, **kwargs): 
     """Optional: bacon""" 
     super().__init__(**kwargs) 


class Spam(Eggs, Bacon): 
    def __init__(self, **kwargs): 
     """Optional: bacon""" 
     super().__init__(**kwargs) 

不过,我有多个类(如可能BaconASpam,但不​​)是关心他们的时候物业bacon已更改。他们不需要修改价值,只需要知道新价值是什么,就像事件一样。由于我已经设置了多重继承性质,这意味着必须通知超类有关更改(如果它关心的话)。

我知道,如果我将类名传递给方法装饰器,或者如果我使用类装饰器,这可能是可能的。我不想拥有所有直接的自我类引用,不得不在每个类的上面创建大量装饰器,或者强制方法使用相同的名称,因为这些都不是pythonic。

我希望得到语法看起来是这样的:

@on_change(bacon) 
    def on_bacon_change(self, bacon): 
     # read from old/new bacon 
     make_eggs(how_much = bacon) 

我不关心的bacon以前的值,使培根的说法是没有必要的,如果这是bacon之后调用已设置。

  • 是否有可能来检查,如果超类与此 装饰的方法?

  • 如果这是不可行的,是否有其他方法可以通过多重继承链传递事件如 ?

编辑:

在垃圾邮件功能的实际调用将在一完成,通过使用@property@bacon.setter,因为这将是初始化bacon最上面级。一旦知道要调用什么函数self,问题只在于将调用传递给MI链。

编辑2:

如果我重写了@bacon.setter属性,是否可以判断是否超()类有bacon二传手?

+1

很明显OP的意思是“{如果super()有一个函数有装饰器”,而不是“如果super()有一个{有装饰器的函数}“ – ninjagecko 2012-02-24 15:42:07

+1

”None“默认主要用于当你真的需要运行一些感兴趣的东西来获得默认值时。这里你可以使用'def foo(self,bacon = 100,** kwargs ):self.ba con = bacon'虽然你应该使用'def __init __(self,** kwargs):self.bacon = kwargs.get('bacon',100)'如果你试图支持在任意kwargs周围洗牌以真正取悦OOP怪人。 – 2012-02-24 15:51:31

+0

@MikeGraham培根的论点是把它从任何通过的'kwargs'中去掉,因为我不认为默认的'object'会对它感到满意。其意图是,每当到达'object'时,每个参数都被剥离出'kwargs'。 – Darthfett 2012-02-24 17:30:40

回答

2

你叫的是什么很可能会很好地适应使用更完整的信号框架等等 - 甚至可能邀请面向方面编程。

不过深入研究它,元类和装饰器可以做你刚才所要求的 - 我想出了这些,我希望它们适合你。

如果你想把它发展到一些强大和可用的东西,请写信给我 - 如果没有这样的东西存在,那么保留一个pipy工具包是值得的。

def setattr_wrapper(cls): 
    def watcher_setattr(self, attr, val): 
     super(cls, self).__setattr__(attr, val) 
     watched = cls.__dict__["_watched_attrs"] 
     if attr in watched: 
      for method in watched[attr]: 
       getattr(self, method)(attr, val) 
    return watcher_setattr 

class AttrNotifier(type): 
    def __new__(metacls, name, bases, dct): 
     dct["_watched_attrs"] = {} 
     for key, value in dct.items(): 
      if hasattr(value, "_watched_attrs"): 
       for attr in getattr(value, "_watched_attrs"): 
        if not attr in dct["_watched_attrs"]: 
         dct["_watched_attrs"][attr] = set() 
        dct["_watched_attrs"][attr].add(key) 
     cls = type.__new__(metacls, name, bases, dct) 
     cls.__setattr__ = setattr_wrapper(cls) 
     return cls 


def on_change(*args): 
    def decorator(meth): 
     our_args = args 
     #ensure that this decorator is stackable 
     if hasattr(meth, "_watched_attrs"): 
      our_args = getattr(meth, "_watched_attrs") + our_args 
     setattr(meth, "_watched_attrs", our_args) 
     return meth 
    return decorator 

# from here on, example of use: 
class A(metaclass=AttrNotifier): 
    @on_change("bacon") 
    def bacon_changed(self, attr, val): 
     print ("%s changed in %s to %s" % (attr, self.__class__.__name__, val)) 


class Spam(A): 
    @on_change("bacon", "pepper") 
    def changed(self, attr, val): 
     print ("%s changed in %s to %s" % (attr, self.__class__.__name__, val)) 

a = A() 
a.bacon = 5 

b = Spam() 
b.pepper = 10 
b.bacon = 20 

(在Python 3.2和Python 2.6测试 - 改变 “A” 类的声明 Python的2元类语法)

编辑 - 上正在做什么 下面是一些话发生了什么: 元类选择标记有“on_close”装饰器的所有方法,然后在该类的字典中注册 - 此字典名为_watched_attrs,它可以作为普通的类属性访问。

元类所做的另一件事是在clas创建后重写__setattr__方法。这个新的__setattr__只是设置属性,然后检查_wacthed_attrs字典,如果该类的任何方法注册为在刚更改的属性被修改时调用 - 如果是,则调用它。

各地watcher_setattr(这是成为每个类的__setattr__有没有让你可以注册不同的属性来对继承链中每个类看着这个函数的额外的间接水平 - 所有的类新有自主承担acessible _watched_attrs字典如果。它不是为了这个,只有继承链_watched_attrs上最专业的类才会被尊重。

+0

在我接受之前需要做一些更多的调查,所有这些元和装饰和递归的东西现在超载我。 :P – Darthfett 2012-02-24 19:14:05

+0

在那里没有“递归”:-)。它看起来很复杂,实际上 - 我会写一些解释性文字。 – jsbueno 2012-02-24 19:39:44

+0

无限递归是一个单独的问题,在我看到你的帖子之前,我试图去思考一个替代方法,哈哈。 非常感谢解释性文字,我认为这将回答我的问题(尽管我可以简化为只支持单一属性)。 – Darthfett 2012-02-24 19:58:05

0

您正在寻找蟒蛇性能

http://docs.python.org/library/functions.html#property

override superclass property setter谷歌搜索导致这个StackOverflow的问题:

Overriding inherited properties’ getters and setters in Python

+0

你可能指的是[这个答案](http://stackoverflow.com/a/9343762/936083)?有没有办法做到这一点作为装饰,或避免直接引用父母的方式? – Darthfett 2012-02-24 17:41:17

+0

我不认为它适用于'Spam'和'Bacon'有setter的情况,但'Eggs'没有,因为'Eggs'不直接从'Bacon'继承。 – Darthfett 2012-02-24 18:07:08