簡體   English   中英

Python - 對繼承感到困惑

[英]Python - Confused about inheritance

我用3個類編寫測試代碼,並使用Chain of Responsibility設計模式,下面的代碼

我打印print(c._abc is b._abc) ,答案是真的,但我原來認為這兩者是不同的。

然后,第2輪,我取消注釋self._abc = kwargs並評論其他3行,答案變為False。

為什么會這樣?

import abc

class A:
    __metaclass__ = abc.ABCMeta

    _abc = {}

    def __init__(self,successor=None,**kwargs):
        self._successor = successor

    @abc.abstractmethod
    def handlerRequest(self):
        pass

class B(A):

    def __init__(self,successor=None,**kwargs):
        self._successor = successor
        print(kwargs)
        # self._abc = kwargs                 # round 2<---uncomment here
        self._abc['a'] = kwargs['a']         # round 2<---comment here
        self._abc['b'] = kwargs['b']         # round 2<---comment here
        self._abc['Hello'] = 'World'         # round 2<---comment here

    def handlerRequest(self):
        if (self._successor is not None):
            self._successor.handlerRequest()

        print(self._abc)

class C(A):

    def handlerRequest(self):
        if (self._successor is not None):
            self._successor.handlerRequest()
        print(self._abc)

list = {'a':1,'b':2}
b = B(**list)
c = C(b)
print(c._abc is b._abc)
c.handlerRequest()

首先只是為了說清楚我想聲明_abc是一個類變量,而不是一個實例變量,因此它的地址空間在父類和子類之間共享。 原始 _abc對象中的任何更改都會影響所有類的_abc對象。 閱讀有關類和實例變量的內容( 此處為SO此處為DO

要檢查_abc共享相同的地址空間,我們可以使用python內置的id()

id()返回對象的“標識”。 這是一個整數(或長整數),保證在該生命周期內該對象是唯一且恆定的。 具有非重疊生存期的兩個對象可以具有相同的id()值。

要在第一輪中檢查這一點,我們可以:

In [33]: id(c._abc)
Out[33]: 4454841440 

In [34]: id(b._abc)
Out[34]: 4454841440

In [36]: id(A._abc)
Out[36]: 4454841440

In [38]: id(B._abc)
Out[38]: 4454841440

In [39]: id(C._abc)
Out[39]: 4454841440

所有這些都為id()提供了相同的值。 在第2輪中,當你取消注釋self._abc = kwargs看看id()的值會發生什么:

In [8]: id(b._abc)
Out[8]: 4585625712 # its different from A._abc and c._abc why?

In [9]: id(c._abc)
Out[9]: 4585627152 # same as A._abc

In [10]: id(A._abc)
Out[10]: 4585627152 # this is same as c._abc

b._abc的值會發生變化,但c._abc和A._abc的值保持不變。 那么,這里到底發生了什么?

在第1輪你做的時候:

# self._abc = kwargs                 
self._abc['a'] = kwargs['a']
self._abc['b'] = kwargs['b']
self._abc['Hello'] = 'World'

您實際上正在修改共享類變量_abc 你的代碼在這里沒有創建一個新的self._abc對象,它正在修改原始的self._abc類變量對象,但在第2輪中你做了:

self._abc = kwargs

這里,代碼將 self._abc kwargs具有自己的地址空間的字典 )分配給self._abc self._abc成為B類的實例變量,它只能用於B類的對象。

要驗證這一點,您可以修改B類以打印ID為:

In [11]: class B(A):
    ...:
    ...:     def __init__(self,successor=None,**kwargs):
    ...:         self._successor = successor
    ...:         print(id(self._abc))
    ...:         print(id(kwargs))
    ...:         self._abc = kwargs
    ...:         print(id(self._abc))

In [12]: b = B(**list)
4585627152 # original self._abc id
4583538904 # kwargs object's id
4583538904 # New self._abc id

正如你可以看到原來有self._abc地址4585627152和kwargs不得不4583538904但經過self._abc= kwargs self._abc的新的ID是4583538904。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM