我正在定义几个用于多重继承的类,例如:
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)
但是,我有多个类(例如可能Bacon
,A
和Spam
,但不是Eggs
)关注何时属性bacon
改变了。他们不需要修改值,只需知道新值是什么,比如事件。由于我已经设置了多重继承性质,这意味着必须通知超类有关更改(如果它关心)。
我知道如果我将类名传递给方法装饰器,或者我使用类装饰器,我可能会这样。我不想拥有所有直接的自我类引用,不得不在每个类上面创建大量的装饰器,或者强制方法是相同的名称,因为这些都不是非常pythonic。
我希望得到类似这样的语法:
@on_change(bacon)
def on_bacon_change(self, bacon):
# read from old/new bacon
make_eggs(how_much = bacon)
我不关心bacon
的先前值,因此如果在设置bacon
之后调用此参数,则不需要培根参数。
是否可以检查超类是否有方法 装饰?
如果这不可行,是否有传递事件的替代方法 这个,通过多继承链?
修改
Spam中函数的实际调用将在A中完成,使用@property
和@bacon.setter
,因为这将是初始化bacon
的最上层类。一旦知道在self
上调用什么函数,问题就在于将调用传播到MI链。
编辑2:
如果我用@bacon.setter
覆盖该属性,是否可以确定super()类是否具有bacon
的setter?
答案 0 :(得分: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__
的函数),以便您可以在继承链上的每个类上注册要监视的不同属性 - 所有classess有独立的_watched_attrs
字典。如果不是这样的话,只有继承链_watched_attrs
上最具特色的类才会得到尊重。
答案 1 :(得分:0)
您正在寻找python 属性:
http://docs.python.org/library/functions.html#property
在Google上搜索override superclass property setter
导致此StackOverflow问题:
Overriding inherited properties’ getters and setters in Python