python 類self詳解

class Box(object):
    def __init__(this, boxname, size, color):
        this.boxname = boxname
        this.size = size
        this.color = color  # self就是用於存儲對象屬性的集合,就算沒有屬性self也是必備的,代表類的實例,而非類。

    def open(this, myself):
        print('-->用自己的myself,打開那個%s,%s的%s' % (myself.color, myself.__dict__['size'], myself.boxname))
        print('-->用類自己的self,打開那個%s,%s的%s' % (this.__dict__['color'], this.__dict__['size'], this.boxname))
    @classmethod
    def close(cls):
        print('-->關閉%s,謝謝' )


b = Box('魔盒', '14m', '紅色')
Box.close() # close是一個類方法,可以通過類調用
b.close()# close是一個類方法,自然也可以通過實例調用

b.open(b)  # 當我們調用b.open(b)時,實際上Python解釋成Box.open(b,b),也就是把self替換成了類的實例b, 另外myself也是一個實例,所以相當於兩個輸入實例參數。
Box.open(b,b)#上面方法實際執行就是這樣的,當我們調用b.open(b)時,實際上Python解釋成Box.open(b,b)。
print(b.__dict__)  # 這裏返回的就是self本身,self存儲屬性,沒有動作。

self的仔細用法。

(1)、self代表類的實例,而非類。

class Test:
    def ppr(self):
        print(self)
        print(self.__class__)

t = Test()
t.ppr()
執行結果:
<__main__.Test object at 0x000000000284E080>
<class '__main__.Test'>

從上面的例子中可以很明顯的看出,self代表的是類的實例。而self.__class__則指向類。
注意:把self換成this,結果也一樣,但Python中最好用約定俗成的self。
(2)、self可以不寫嗎?
在Python解釋器的內部,當我們調用t.ppr()時,實際上Python解釋成Test.ppr(t),也就是把self替換成了類的實例。

class Test:
    def ppr():
        print(self)

t = Test()
t.ppr()

 

運行結果如下:

Traceback (most recent call last):
  File "cl.py", line 6, in <module>
    t.ppr()
TypeError: ppr() takes 0 positional arguments but 1 was given

 

運行時提醒錯誤如下:ppr在定義時沒有參數,但是我們運行時強行傳了一個參數。

由於上面解釋過了t.ppr()等同於Test.ppr(t),所以程序提醒我們多傳了一個參數t。

這裏實際上已經部分說明了self在定義時不可以省略。

當然,如果我們的定義和調用時均不傳類實例是可以的,這就是類方法。

class Test:
    @classmethod
    def ppr(cls):
        print(__class__)

Test.ppr()

運行結果:
<class '__main__.Test'>

 

(3)、在繼承時,傳入的是哪個實例,就是那個傳入的實例,而不是指定義了self的類的實例。

class Parent:
    def pprt(self):
        print(self)

class Child(Parent):
    def cprt(self):
        print(self)
c = Child()
c.cprt()
c.pprt()
p = Parent()
p.pprt()

 

運行結果:

<__main__.Child object at 0x0000000002A47080>
<__main__.Child object at 0x0000000002A47080>
<__main__.Parent object at 0x0000000002A47240>

 

解釋:
運行c.cprt()時應該沒有理解問題,指的是Child類的實例。
但是在運行c.pprt()時,等同於Child.pprt(c),所以self指的依然是Child類的實例,由於self中沒有定義pprt()方法,所以沿着繼承樹往上找,發現在父類Parent中定義了pprt()方法,所以就會成功調用。

(4)、在描述符類中,self指的是描述符類的實例

class Desc:
    def __get__(self, ins, cls):
        print('self in Desc: %s ' % self )
        print(self, ins, cls)
class Test:
    x = Desc()
    def prt(self):
        print('self in Test: %s' % self)
t = Test()
t.prt()
t.x

 

運行結果如下:

self in Test: <__main__.Test object at 0x0000000002A570B8>
self in Desc: <__main__.Desc object at 0x000000000283E208>
<__main__.Desc object at 0x000000000283E208> <__main__.Test object at 0x0000000002A570B8> <class '__main__.Test'>

 

這裏主要的疑問應該在:Desc類中定義的self不是應該是調用它的實例t嗎?怎麼變成了Desc類的實例了呢?
因爲這裏調用的是t.x,也就是說是Test類的實例t的屬性x,由於實例t中並沒有定義屬性x,所以找到了類屬性x,而該屬性是描述符屬性,爲Desc類的實例而已,所以此處並沒有頂用Test的任何方法。

那麼我們如果直接通過類來調用屬性x也可以得到相同的結果。

下面是把t.x改爲Test.x運行的結果。

self in Test: <__main__.Test object at 0x00000000022570B8>
self in Desc: <__main__.Desc object at 0x000000000223E208>
<__main__.Desc object at 0x000000000223E208> None <class '__main__.Test'>

 

總結:以上是之前學習Python時的小結,現在已博客方式呈現,同時爲pyspark中調用self遇到的問題做鋪墊,後面也會對比java,未完待續…….

                    <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/production/markdown_views-ea0013b516.css">
                        </div>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章