请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

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

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

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))```

正在回答 回答被采纳积分+3

2回答

bobby 2021-12-11 12:07:14

在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 回复 有任何疑惑可以回复我~
  • 提问者 慕标1049315 #1
    谢谢老师,明白了!
    回复 有任何疑惑可以回复我~ 2021-12-14 10:35:51
bobby 2021-12-04 22:52:22
self.wealth += get

 执行完以后 wealth = 100

self.wealth -= house_price

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

0 回复 有任何疑惑可以回复我~
  • 提问者 慕标1049315 #1
    Son(20) 初始化后wealth应该是20,然后增加100,扣除120,余额应该是0。老师可以调试看看,调用父类的构造方法和give方法时,子类的wealth都会被改变。
    回复 有任何疑惑可以回复我~ 2021-12-07 09:31:11
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信