Python 在不调用super()的情况下执行父类方法
我们的班级结构如下:Python 在不调用super()的情况下执行父类方法,python,python-3.x,class,inheritance,Python,Python 3.x,Class,Inheritance,我们的班级结构如下: 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
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)
我希望在调用PhoneCaller.phone()
时执行NamePrinter.phone()
,而不必在PhoneCaller中提及super.phone()
这样做的目的是,当PhoneCaller.phone被执行时,应用于PhoneCaller以使其执行NamePrinter的行为的唯一修改是PhoneCaller从父级继承,仅此而已。特别是,不需要修改任何单个PhoneCaller方法
简单来说:
- PhoneCaller从NamePrinter继承=>在编写号码之前打印姓名
- PhoneCaller不从NamePrinter继承=>未打印名称
- 不需要在PhoneCaller.phone中乱来
这可能吗?是的,至少在元类中是可能的:
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
还有另一个解决方案是decorator。它使您免于滥用继承,并且更加清晰和灵活(IMHO):
在
classnameprinter
重命名为def\u phone(self):
中,在def phone(self):
doself.\u phone()。如果是这样,为什么不先定义两个类,然后正确地定义NamePrinter
的子类呢?这似乎是一个巨大的XY问题。请参见导入此
:“显式优于隐式”。@chepner现实世界中的情况是,我们有几十个不同的子类,我们需要一个简单的开关来触发另一种行为,这取决于此开关的打开或关闭看起来很棒。Python方面有点遗憾,因为它不得不通过这些恶作剧来实现一个非常简单的概念。。。回答得很好。@Jivan在运行时重写现有代码并不“简单”。@chepner我很想听到一个更好的解决方案来解决这个用例,如果你有一个我完全开放的解决方案,我会取消不能修改PhoneCaller
的限制。
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()