我们具有以下类结构:
class NamePrinter():
def phone():
print(self.name)
def email():
print(self.name)
class PhoneCaller(NamePrinter):
def __init__(self, name, number, mail):
self.name = name
self.number = number
self.mail = mail
def phone(self):
# here, NamePrinter.phone() should be executed
compose_number(self.number)
def email(self):
# here, NamePrinter.email() should be executed
compose_mail(self.mail)
我希望在调用NamePrinter.phone()
时执行PhoneCaller.phone()
,而不必在PhoneCaller中提及super.phone()
。
这个想法是,为了执行PhoneCaller.phone时执行NamePrinter的行为而对PhoneCaller进行的唯一修改是,PhoneCaller继承自父对象,仅此而已。特别是,无需修改任何单独的PhoneCaller方法。
简单点说
这可能吗?
答案 0 :(得分:2)
是的,至少有可能使用元类:
def new_attr(attr_name, attr):
name_printer_attr = getattr(NamePrinter, attr_name)
def _new_attr(self, *args, **kwargs):
name_printer_attr(self)
return attr(self, *args, **kwargs)
return _new_attr
class Meta(type):
def __new__(cls, name, bases, attrs):
if name == 'NamePrinter':
cls.attrs = attrs
else:
for attr_name, attr in attrs.items():
if callable(attr) and attr_name in cls.attrs:
attrs[attr_name] = new_attr(attr_name, attr)
return type.__new__(cls, name, bases, attrs)
class NamePrinter(metaclass=Meta):
def phone(self):
print('NamePrinter phone')
class PhoneCaller1:
def phone(self):
print('PhoneCaller1 phone')
class PhoneCaller2(NamePrinter):
def phone(self):
print('PhoneCaller2 phone')
p1 = PhoneCaller1()
p1.phone() # will print only "PhoneCaller1 phone"
p2 = PhoneCaller2()
p2.phone() # will print "NamePrinter phone" and "PhoneCaller2 phone" on next line
答案 1 :(得分:1)
还有一个带有装饰器的解决方案。它可以避免滥用继承,并且更加清晰灵活(IMHO):
def new_attr(attr_name, attr, from_cls):
from_cls_attr = getattr(from_cls, attr_name)
def _new_attr(self, *args, **kwargs):
from_cls_attr(self)
return attr(self, *args, **kwargs)
return _new_attr
def use_methods(from_cls):
dir_from_cls = dir(from_cls)
def modify(cls):
for attr_name in dir(cls):
if not attr_name.startswith('__') and attr_name in dir_from_cls:
attr = getattr(cls, attr_name)
if callable(attr):
setattr(cls, attr_name, new_attr(attr_name, attr, from_cls))
return cls
return modify
class NamePrinter:
def phone(self):
print('NamePrinter phone')
class PhoneCaller1:
def phone(self):
print('PhoneCaller1 phone')
@use_methods(NamePrinter)
class PhoneCaller2:
def phone(self):
print('PhoneCaller2 phone')
p1 = PhoneCaller1()
p1.phone()
p2 = PhoneCaller2()
p2.phone()