简体   繁体   English

在现代 Python 中扩展父 class 方法的正确方法是什么

[英]What is the correct way to extend a parent class method in modern Python

I frequently do this sort of thing:我经常做这样的事情:

class Person(object):
    def greet(self):
        print "Hello"

class Waiter(Person):
    def greet(self):
        Person.greet(self)
        print "Would you like fries with that?"

The line Person.greet(self) doesn't seem right. Person.greet(self) 行似乎不正确。 If I ever change what class Waiter inherits from I'm going to have to track down every one of these and replace them all.如果我要更改 class Waiter 从中继承的内容,我将不得不追踪其中的每一个并将它们全部替换。

What is the correct way to do this is modern Python?现代 Python 的正确方法是什么? Both 2.x and 3.x, I understand there were changes in this area in 3. 2.x 和 3.x,我知道在 3.x 中这方面有变化。

If it matters any I generally stick to single inheritance, but if extra stuff is required to accommodate multiple inheritance correctly it would be good to know about that.如果有任何问题,我通常坚持使用单个 inheritance,但如果需要额外的东西来正确容纳多个 inheritance,那么了解这一点会很好。

You use super : 你用super

Return a proxy object that delegates method calls to a parent or sibling class of type. 返回将方法调用委托给父类或兄弟类类型的代理对象。 This is useful for accessing inherited methods that have been overridden in a class. 这对于访问已在类中重写的继承方法很有用。 The search order is same as that used by getattr() except that the type itself is skipped. 搜索顺序与getattr()使用的搜索顺序相同,只是跳过了类型本身。

In other words, a call to super returns a fake object which delegates attribute lookups to classes above you in the inheritance chain. 换句话说,对super的调用返回一个伪对象,该对象将属性查找委托给继承链中的上面的类。 Points to note: 注意事项:

  • This does not work with old-style classes -- so if you are using Python 2.x, you need to ensure that the top class in your hierarchy inherits from object . 这不适用于旧式类 - 因此,如果您使用的是Python 2.x,则需要确保层次结构中的顶级类继承自object
  • You need to pass your own class and instance to super in Python 2.x. 您需要在Python 2.x中将您自己的类和实例传递给super This requirement was waived in 3.x. 该要求在3.x中被免除。
  • This will handle all multiple inheritance correctly. 这将正确处理所有多重继承。 (When you have a multiple inheritance tree in Python, a method resolution order is generated and the lookups go through parent classes in this order.) (如果在Python中有多重继承树,则会生成方法解析顺序 ,并且查找按此顺序通过父类。)

Take care: there are many places to get confused about multiple inheritance in Python. 小心:有很多地方对Python中的多重继承感到困惑。 You might want to read super() Considered Harmful . 你可能想读super() Considered Harmful If you are sure that you are going to stick to a single inheritance tree, and that you are not going to change the names of classes in said tree, you can hardcode the class names as you do above and everything will work fine. 如果您确定要坚持使用单个继承树,并且不打算更改所述树中类的名称,则可以像上面那样对类名进行硬编码,一切都会正常工作。

Not sure if you're looking for this but you can call a parent without referring to it by doing this. 不确定你是否正在寻找这个,但你可以通过这样做来打电话给父母而不参考它。

super(Waiter, self).greet()

This will call the greet() function in Person . 这将调用Persongreet()函数。

katrielalex's answer is really the answer to your question, but this wouldn't fit in a comment. katrielalex的答案确实是你问题的答案,但这不符合评论。

If you plan to go about using super everywhere, and you ever think in terms of multiple inheritance, definitely read the "super() Considered Harmful" link. 如果你计划到处使用super ,并且你曾经想过多重继承,那么一定要阅读“super()Considered Harmful”链接。 super() is a great tool, but it takes understanding to use correctly. super()是一个很棒的工具,但正确使用它需要理解。 In my experience, for simple things that don't seem likely to get into complicated diamond inheritance tangles, it's actually easier and less tedious to just call the superclass directly and deal with the renames when you change the name of the base class. 根据我的经验,对于似乎不太可能进入复杂的钻石继承缠结的简单事物,直接调用超类并在更改基类名称时处理重命名实际上更容易也更少繁琐。

In fact, in Python2 you have to include the current class name, which is usually more likely to change than the base class name. 事实上,在Python2中,您必须包含当前的类名,它通常比基类名更改。 (And in fact sometimes it's very difficult to pass a reference to the current class if you're doing wacky things; at the point when the method is being defined the class isn't bound to any name, and at the point when the super call is executed the original name of the class may not still be bound to the class, such as when you're using a class decorator) (事实上​​,如果你正在做古怪的事情,有时很难将引用传递给当前类;在定义方法时,类没有绑定任何名称,并且在super调用是执行类的原始名称可能仍然不会绑定到类,例如当您使用类装饰器时)

I'd like to make it more explicit in this answer with an example.我想通过一个例子在这个答案中更明确地说明这一点。 It's just like how we do in JavaScript .这就像我们在 JavaScript 中所做的一样 The short answer is, do that like we initiate the constructor using super .简短的回答是,就像我们使用super启动构造函数一样。

class Person(object):                                                             
   def __init__(self, name):                                                      
       self.name = name                                                           
                                                                                    
   def greet(self):                                                               
       print(f"Hello, I'm {self.name}")                                           
                                                                                    
class Waiter(Person):                                                             
    def __init__(self, name):                                                     
        super().__init__(name)
        # initiate the parent constructor
        # or super(Waiter, self).__init__(name)                                                    
                                                                                    
    def greet(self):                                                              
        super(Waiter, self).greet()                                               
        print("Would you like fries with that?")                                  
                                                                                    
waiter = Waiter("John")                                                           
waiter.greet()

# Hello, I'm John
# Would you like fries with that?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM