Python advanced syntax _ discuss multiple inheritance and MRO order

Discuss multiple inheritance and MRO order again

MRO order in multiple inheritance

Separately call the method of the parent class

print("******多继承使用类名.__init__ 发生的状态******")
class Parent(object):
    def __init__(self, name):
        print('parent的init开始被调用')
        self.name = name
        print('parent的init结束被调用')

class Son1(Parent):
    def __init__(self, name, age):
        print('Son1的init开始被调用')
        self.age = age 
        Parent.__init__(self, name)
        print('Son1的init结束被调用')

class Son2(Parent):
    def __init__(self, name, gender):
        print('Son2的init开始被调用')
        self.gender = gender
        Parent.__init__(self, name)
        print('Son2的init结束被调用')

class Grandson(Son1, Son2):
    def __init__(self, name, age, gender):
        print('Grandson的init开始被调用')
        Son1.__init__(self, name, age)  # 单独调用父类的初始化方法
        Son2.__init__(self, name, gender)
        print('Grandson的init结束被调用')

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)

print("******多继承使用类名.__init__ 发生的状态******\n\n")

operation result:

******多继承使用类名.__init__ 发生的状态******
Grandson的init开始被调用
Son1的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son1的init结束被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
******多继承使用类名.__init__ 发生的状态******

In multiple inheritance, the super call has the overridden method of the parent class

print("******多继承使用super().__init__ 发生的状态******")
class Parent(object):
    def __init__(self, name, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
        print('parent的init开始被调用')
        self.name = name
        print('parent的init结束被调用')

class Son1(Parent):
    def __init__(self, name, age, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
        print('Son1的init开始被调用')
        self.age = age
        super().__init__(name, *args, **kwargs)  # 为避免多继承报错,使用不定长参数,接受参数
        print('Son1的init结束被调用')

class Son2(Parent):
    def __init__(self, name, gender, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
        print('Son2的init开始被调用')
        self.gender = gender
        super().__init__(name, *args, **kwargs)  # 为避免多继承报错,使用不定长参数,接受参数
        print('Son2的init结束被调用')

class Grandson(Son1, Son2):
    def __init__(self, name, age, gender):
        print('Grandson的init开始被调用')
        # 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍
        # 而super只用一句话,执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因
        # super(Grandson, self).__init__(name, age, gender)
        super().__init__(name, age, gender)
        print('Grandson的init结束被调用')

print(Grandson.__mro__)

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
print("******多继承使用super().__init__ 发生的状态******\n\n")

operation result:

******多继承使用super().__init__ 发生的状态******
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson的init开始被调用
Son1的init开始被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Son1的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
******多继承使用super().__init__ 发生的状态******

note:

  • The execution results of the above 2 codes are different
  • If two subclasses inherit the parent class, when called by the parent class name in the subclass, parent is executed twice
  • If both subclasses inherit the parent class, when the super class is called in the subclass, the parent is executed once

*args, **kwargs other use -> unpacking

Code example:

def test2(a, b, *args, **kwargs):
	print("--------")
	print(a)
	print(b)
	print(args)
	print(kwargs)


def test1(a, b, *args, **kwargs):
	print("--------")
	print(a)
	print(b)
	print(args)
	print(kwargs)

	# test2(a, b, args, kwargs)  # 相当于test2(11, 22, (33, 44, 55, 66), {"name":"Neo", "age":"18"})
	# test2(a, b, *args, kwargs)  # 相当于test2(11, 22, 33, 44, 55, 66, {"name":"Neo", "age":"18"})
	test2(a, b, *args, **kwargs)  # 相当于test2(11, 22, 33, 44, 55, 66, "name":"Neo", "age":"18")


test1(11, 22, 33, 44, 55, 66, name="Neo", age=18)

In fact vernacular explanation is that when the function is to guarantee that the received 不定常parameters, can *argsnot be received extra parameter names stored in the form of tuples; by **kwargsparameters received extra band name, stored as a dictionary.

And the function test2(a, b, *args, **kwargs)represented by the unpacking, the split values into a tuple, split into the dictionary, and assign the corresponding variables.

MRO in single inheritance

Single inheritance super

print("******单继承使用super().__init__ 发生的状态******")
class Parent(object):
    def __init__(self, name):
        print('parent的init开始被调用')
        self.name = name
        print('parent的init结束被调用')

class Son1(Parent):
    def __init__(self, name, age):
        print('Son1的init开始被调用')
        self.age = age
        super().__init__(name)  # 单继承不能提供全部参数
        print('Son1的init结束被调用')

class Grandson(Son1):
    def __init__(self, name, age, gender):
        print('Grandson的init开始被调用')
        super().__init__(name, age)  # 单继承不能提供全部参数
        print('Grandson的init结束被调用')

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
#print('性别:', gs.gender)
print("******单继承使用super().__init__ 发生的状态******\n\n")

to sum up:

  • super().__init__ is relative to the class name. init , the usage is basically the same in single inheritance

  • But there is a difference in multiple inheritance. The super method can ensure that the method of each parent class will only be executed once, and the method using the class name will cause the method to be executed multiple times, depending on the previous output result.

  • In the case of multiple inheritance, use the super method to pass parameters to the parent class. It should be due to the super algorithm in python. All parameters must be passed, otherwise an error will be reported

  • In single inheritance, using the super method, you cannot pass all the parameters, only the parameters required by the parent method, otherwise an error will be reported

  • In the case of multiple inheritance, instead of using the class name.__init__ method, each parent class must be written once, while using the super method, all the methods of the parent class will be executed by just writing one sentence, which is why multiple inheritance requires all One reason for passing on

Inherited interview questions

What will be the output of the following code? Say your answer and explain.

class Parent(object):
    x = 1

class Child1(Parent):
    pass

class Child2(Parent):
    pass

print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)

The answer, the output of the above code is:

1 1 1
1 2 1
3 2 3

Answer analysis:

What makes you confused or surprised is that the output on the last line is 3 2 3 instead of 3 2 1. Why does changing the value of Parent.x also change the value of Child2.x, but at the same time the value of Child1.x does not change?

The key to this answer is that in Python, class variables are handled as dictionaries internally. If the name of a variable is not found in the dictionary of the current class, the ancestor class (such as the parent class) will be searched until the referenced variable name is found (if the referenced variable name is neither in its own class nor in its ancestor If found in the class, an AttributeError exception will be raised).

Therefore, setting x = 1 in the parent class will make the class variable x value 1 in the reference to this class and any of its subclasses. This is because the output of the first print statement is 1 1 1.

Subsequently, if any of its subclasses overwrite the value (for example, we execute the statement Child1.x = 2), then the value is only changed in the subclass. This is why the output of the second print statement is 1 2 1.

Finally, if the value is changed in the parent class (for example, we execute the statement Parent.x = 3), this change will affect any value in the subclass that does not override the value (the affected child in this example The class is Child2). This is why the third print output is 3 2 3.

Guess you like

Origin blog.csdn.net/weixin_42250835/article/details/89888314