简体   繁体   中英

What is the difference between assignment and overriding in a child class?

This has been bugging me for a while and appears hard to google.

In the following code can anyone explain the pragmatic difference between FirstChild and SecondChild . It's clear from experiments that both "work" and arguably SecondChild is marginally more efficient. But is there something that I'm missing about the way these two behave? Are they different and how are they different?

import collections


class Parent:

    def send_message(self, message: str):
        pass


class FirstChild(Parent):

    def __init__(self):
        self.message_queue = collections.deque()

    def send_message(self, message: str):
        self.message_queue.append(message)


class SecondChild(Parent):

    def __init__(self):
        self.message_queue = collections.deque()
        self.send_message = self.message_queue.append

FirstChild creates a descriptor in the class called send_message . When you do instance.send_message , the interpreter first searches the instance __dict__ for the name, then the class. When it's found in the class, the function is bound to the instance to create a method object that doesn't accept self . It happens every time you do the lookup, and it looks something like

method = type(instance).send_message.__get__(type(instance), instance)

SecondChild assigns a bound method as the attribute send_message in the instance . It cuts out the lookup in its own class object, as well as the lookup in the deque class object, and binding. That is probably why it appears marginally more efficient.

A major practical difference between these approaches is that send_message in SecondChild is not overridable. Since functions are non data descriptors (they have a __get__ method but not __set__ (and yes, functions have a class type and methods, like any other object)), the instance attribute send_message in SecondChild will always trump any class-level function. This means that a child of SecondChild that calls the parent __init__ method will hide any implementation of send_message it creates.

You will likely find the official descriptor guide to be quite informative: https://docs.python.org/3/howto/descriptor.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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