Python 中的self是學習類的一個難點,很多初學者學到Python self的時候,都會出現難以了解的情況,下面,蝸牛部落格就為您進行講解一下Python中的self。
Updated on Nov-02-2018:
一、首先要明确幾個概念:
1. self代表類的執行個體,而非類。
例:
class Person:
def pri(self):
print(self)
a = Person()
a.pri()
print(id(a))
運作結果:
<__main__.Person object at0x04B37A90>
78871184
将0x04B37A90轉換成十進制為78871184,與self的id相同,說明在這裡self代表的是執行個體a的id位址。
下面這個例子其實更好:
首先定義一個函數:
class TestSelf:
def self_id(self):
return self # 傳回self自身
t1 = TestSelf() # 執行個體化為一個對象t1
print(t1) # 列印t1對象自身,
print(t1.self_id()) # 列印t1對象的self_id方法的傳回值
# 輸出
# <__main__.TestSelf object at 0x1055afbe0>
# <__main__.TestSelf object at 0x1055afbe0>
print(t1 is t1.self_id()) # 使用is判斷他們的指向是否一緻
# 輸出
# True
那麼我們就可以看到有這樣的寫法;
class MainEngine:
"""
"""
def add_engine(self, engine_class: Any):
"""
Add function engine.
"""
engine = engine_class(self, self.event_engine)
self.engines[engine.engine_name] = engine
其中的engine = engine_class(self, self.event_engine)相當于engine = engine_class(mainEngine(), self.event_engine)
2. self可以不寫嗎
(1)編寫類中的函數時,不寫self會報錯。
例:如下面這個最簡單的類可以正常運作的,如果删除def prt(self)中的self,就會報“TypeError: enten88() takes no arguments (1 given)”的錯誤。
class Test(object):
def prt():
print("this is test")
b = Test()
b.prt()
這其實與class中函數調用的方式有關,在給出一個執行個體以後,我們調用類中的具體方法(即函數)時,預設傳入了self參數(即執行個體位址),如上面的執行個體,我們在定義函數時沒有給他形參,那麼調用時自動傳入的第一個參數self無處容納,即參數多餘,報錯。
(2)沒有self可以運作
下面的代碼其實是可以運作的。因為這裡沒有調用執行個體,沒有self傳入,那麼也就不向pri傳遞參數了(特例)。
class Person:
def pri():
print('test successfully')
Person.pri()
上面是python3的版本,但是在python2.x下面
class Person(object):
def pri():
print 'test successfully'
Person.pri()
會報錯:
Traceback (most recent call last):
File "test.py", line 59, in
Person.pri()
TypeError: unbound method pri() must be called with Person instance as first arg
ument (got nothing instead)
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()方法,是以就會成功調用。
更多知識可以看這裡:http://python.jobbole.com/81921/
二、self與變量
class Test(object):
quip = "This is a test!"
def prt(self):
print quip
b = Test()
b.prt()
會報錯:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuATOzEDch52UvwFNw8CX3EDMy8CXzRWYvxGc19CX05WZ052bj1Cc39CXt92YukXYk9GdslWYuNnL3d3dvw1LcpDc0RHaiojIsJye.png)
這時,隻需要将
print quip
改成:
print self.quip
或者
print Test.quip
就可以正常顯示結果了。
三、self必須是self嗎?
我們先看一個标準類的寫法:
class Song():
def __init__(self,lyrics):
self.lyric = lyrics
def sing_me_a_song(self):
for line in self.lyric:
print line
happy_baby = Song(['happy birthday to you',
'I do not want to get sued',
'So i will stop right there'])
bulls_on_parade = Song(['They rally around the family',
'with pockets full of shells'])
happy_baby.sing_me_a_song()
bulls_on_parade.sing_me_a_song()
運作結果如下:
說明:在代碼:
self.lyric = lyrics
中,等号左邊的那個lyric是執行個體的屬性,後面那個lyric是方法__init__的參數,兩個是不同的
然後,我将将代碼改成如下的形式:
class Song():
def __init__(me,lyrics):
me.a = lyrics
def sing_me_a_song(me):
for line in me.a:
print line
happy_baby = Song(['happy birthday to you',
'I do not want to get sued',
'So i will stop right there'])
bulls_on_parade = Song(['They rally around the family',
'with pockets full of shells'])
happy_baby.sing_me_a_song()
bulls_on_parade.sing_me_a_song()
程式照樣能運作,且運作的結果一模一樣。
那麼,我們可不可以不用這個self(或者其他名稱),比如将代碼中的
self.lyric = lyrics
直接改成呢?
lyric = lyrics
您可以自己試一試,答案是不行的,這樣等于定義了一個全局的變量。
是以我們可以得出如下的結論:
Self是必須的,但是名稱不一定必須是self,你可以改成做任意的其他名字,不過在一個類中,定義所有的函數時都必須統一用這一個名字,比如上面的例子中,要麼統一用self,要麼統一用me,不能在一個類中,又有self,又有me。