子类继承父类时,变量相互影响

来源:4-5 类变量和实例变量

慕标1049315

2021-12-03

老师,我这边写了个测试例子。但意外发现一个现象。想在子类中调用父类方法。但是有一个实例变量在子类和父类中相互影响(操作的是同一个对象)。请问老师,该怎么解释和避免这种现象呢?

class Father:
    love = True

    def __init__(self, wealth):
        self.wealth = wealth

    def give(self):
        self.wealth -= 100
        return 100


class Son(Father):
    def __init__(self, wealth):
        self.wealth = wealth
        super().__init__(wealth=100)

    def buy_house(self):
        get = super().give()
        print('爸爸给了我{}万'.format(get))
        self.wealth += get
        house_price = 120
        self.wealth -= house_price


if __name__ == "__main__":
    s = Son(20)
    s.buy_house()
    print('买完房后,我的余额{}'.format(s.wealth))```

写回答

2回答

bobby

2021-12-11

在python继承中,子类的init()方法中需要初始化父类的属性,常常会用到super(child, self).init(arg1, arg2)这样的方法。

下面思考一下如下几个问题:

1.如果在子类的构造函数中需要初始化父类的属性,一般需要使用super,是否可以使用同名的属性来进行初始化。

看几个例子:

使用self.value复制的方式:

class P(object):

    def __init__(self):
        self.value = 0
        print "++++++"
        print id(self.value)

    def get(self):
        print "p get"
        print self.value
        return id(self.value)


class C(P):

    def __init__(self):
        print "start"
        self.value = 44 #两句交换一下位置看看
        #super(C, self).__init__() #标准的写法是这样的, 先调用父类构造函数
        print id(self.value)
        print "======="
        print id(self.value)

    def get(self):
        print "c get"
        print self.value
        return id(self.value)

    def getsuper(self):
        return super(C, self).get()

c = C()
print c.get()
print "----------"
print c.getsuper()
➜  ~ python object.py
start
19263528
=======
19263528
c get
44
19263528
----------
p get
44
19263528

分析结果:
从结果可以看到,父类和子类的同名成员是同一个id。

使用super方式,修改一下代码:

class P(object):

    def __init__(self):
        self.value = 0
        print "++++++"
        print id(self.value)

    def get(self):
        print "p get"
        print self.value
        return id(self.value)


class C(P):

    def __init__(self):
        print "start"
        #self.value = 44 #两句交换一下位置看看
        super(C, self).__init__() #标准的写法是这样的, 先调用父类构造函数
        print id(self.value)
        print "======="
        print id(self.value)

    def get(self):
        print "c get"
        print self.value
        return id(self.value)

    def getsuper(self):
        return super(C, self).get()
c = C()
print c.get()
print "----------"
print c.getsuper()

输出结果:

➜  ~ python object.py
start
++++++
22908032
22908032
=======
22908032
c get
0
22908032
----------
p get
0
22908032

分析结果:
如果使用super来初始化父类属性,可以看到,结果是一样的。

如果有两个初始化的操作

class P(object):

    def __init__(self):
        self.value = 0
        print "++++++"
        print id(self.value)

    def get(self):
        print "p get"
        print self.value
        return id(self.value)


class C(P):

    def __init__(self):
        super(C, self).__init__() #标准的写法是这样的, 先调用父类构造函数
        print "start"
        self.value = 44 #两句交换一下位置看看
        print id(self.value)
        print "======="
        print id(self.value)

    def get(self):
        print "c get"
        print self.value
        return id(self.value)

    def getsuper(self):
        return super(C, self).get()
c = C()
print c.get()
print "----------"
print c.getsuper()


输出结果:

➜  ~ python object.py
++++++
10316928
start
10317864
=======
10317864
c get
44
10317864
----------
p get
44
10317864

分析结果:
可以看出来结果有些不同,这是因为后一个初始化方法会覆盖前一个初始化方法。即self.value会覆盖super(C, self)._init_(),所以会有两个id,但是get方法得到的都是id,都是后面一个value的id。


2.为什么一般都是用super这种方式来初始化父类的属性,而不用self.value = xxx这种方式。

该例子中是因为父类的属性并不是特别多,所以并没有什么影响,如果子类需要继承的父类属性较多,可能就会比较麻烦,所以我们一般使用super来初始化父类属性。



0
1
慕标1049315
谢谢老师,明白了!
2021-12-14
共1条回复

bobby

2021-12-04

self.wealth += get

 执行完以后 wealth = 100

self.wealth -= house_price

执行完以后是 -20 这里没有看出来有什么问题啊

0
1
慕标1049315
Son(20) 初始化后wealth应该是20,然后增加100,扣除120,余额应该是0。老师可以调试看看,调用父类的构造方法和give方法时,子类的wealth都会被改变。
2021-12-07
共1条回复

Python3高级核心技术97讲,高级进阶的必学课程

socket编程/多线程/多进程/线程池/asyncio并发编程/协程和异步IO

2121 学习 · 551 问题

查看课程