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):
do
self.\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()