1. 程式人生 > 實用技巧 >python——類中的self到底的作用及三個應用場景

python——類中的self到底的作用及三個應用場景

原文:https://www.cnblogs.com/vincent-sh/p/12780716.html

class Test(object):
  def __init__ (self, val1):
    self.val0 = val1
  def fun1(self):
    print(self.val0)
  def fun2(self, val2):
    print(val2)
  def fun3(self):
    print(self.fun1)
    self.fun1()


ins=Test(123)
ins.new_val=”I’m a new value” # 在例項中新增資料屬性

1、self是什麼
在python的類中self代表例項本身,具體來說,是該例項的記憶體地址。
在呼叫例項的方法時,Python直譯器會自己把例項!!變數!!傳給類的函式中的self。
以上述程式碼I為例,程式碼I定義了一個類Test,在這個類中,self為引數變數,在類Test例項化得到例項ins時,python直譯器自動呼叫__init__,執行Test.init(ins, 123),該self可接收例項ins的記憶體地址,從而self代表了例項本身。類似的,如果例項化ins後,執行ins.fun1( ),python直譯器會將ins.fun1( )解釋成Test.fun1(ins)。可見,self這個變數是無需使用者手動傳送值的,直譯器會自動幫我們給其傳遞例項。

需要注意的是,self不是關鍵字,換言之,可以用其它的合法變數名替換self,但是,規範和標準建議我們一致使用self。

2、self的使用場景
在類中,self的使用有下面3個場景:
1)self為類中的函式的第一個引數,例如在類中,def fun1(self, …)。
上文說過,“在呼叫例項的方法時,Python直譯器會自己把例項變數傳給類的函式中的self”,如果類的函式的第一個引數不是代表例項的self,則呼叫例項的方法時,該方法沒有引數接收直譯器自動傳入的例項變數,從而程式會產生異常。
事實上,“和普通的函式相比,在類中定義的函式只有一點不同,就是第一個引數永遠是例項變數self,並且,呼叫時,不用傳遞該引數。除此之外,類的方法和普通函式沒有什麼區別,所以,你仍然可以用預設引數、可變引數、關鍵字引數和命名關鍵字引數”(廖雪峰老師說的)。

2)在類中,引用例項的屬性,示例:self.變數名(如self.val0)。
引用例項的屬性的目的是為例項繫結屬性、寫入或讀取例項的屬性。
例如,在程式碼I中,在類的函式__init__中,“self.val1 = val1”將屬性val0繫結到了例項self(類例項化成ins後,self就代表例項ins了)上,並且將變數val1的值賦給了例項的屬性val0。在函式fun1中,print(self.val0),讀取了例項self的值val0,並打印出來,當然,在函式中修改屬性val0的值也是可以的。

3)在類中,呼叫例項的方法,例如,self.fun1();獲取例項的方法的地址,例如self.fun1。
類是抽象的模板,而例項是根據類創建出來的一個個具體的“物件”,每個物件都擁有相同的方法,但各自的資料可能不同。既然,self代表例項,則可以“self.函式名”的方式表示例項的方法地址,以“self.函式名()”的方式,呼叫例項的方法。在類的定義中,以及例項化後對例項方法的呼叫,都可以這樣做。

3、python的幾種變數——按作用域分
1、全域性變數:在模組內、在所有函式外面、在class外面,這就是全域性變數。
2、區域性變數:在函式內、在class的方法內(未加self修飾的) ,這就是區域性變數
3、靜態變數(也可以說,類屬性):在class內的,但不在class的方法內的,這就是靜態變數
4、例項變數(也可以說,例項屬性):在class的方法內的,用self修飾的變數,這就是例項變數

4、self和變數的關係
綜合上述的1、2和3點,可以得到在類中,self和變數的關係了,一言以蔽之,被self修飾的變數是例項變數,不被self修飾的變數不是例項變數。
例項變數有什麼作用,或者說,什麼時候應該使用self修飾變數比較好?我的總結如下:
當我們想將某個變數繫結給例項時,就在類中,使用self修飾該變數。一般來說,類例項化為不同例項後,為了不同例項的某一變數互不干擾,就將該變數繫結給例項。
具體的使用場景,
1)若需要在類的不同方法中呼叫同一變數,且屬於同一個類的不同例項的該變數互不影響(即排除類屬性),則在類中將該變數繫結給例項。
2)需要在類例項化得到例項後,修改、或引用例項的某變數,則在類中將該變數繫結給例項。

a = 1   
def say():  
    print '呼叫了全域性方法'  
class people:  
    a = 100  
    def say(self):  
        print '呼叫了類的方法'  
    def do(self):  
        say()  
        self.say()  
        print 'a = ' , a  
        print 'self.a = ' , self.a  
p = people()   
p.do()  
>>>
  1. 呼叫了全域性方法
  2. 呼叫了類的方法
  3. a=1
  4. self.a=100
Python中,類之外可以定義很多全域性變數和函式,這是它與java明顯的不同。為了直譯器準確的找到函式或變數,需要使用self來限定方法變數的區域,這樣直譯器就能快速知道你呼叫的是類中的變數還是全域性的變量了。

5、一點補充
為例項繫結屬性有兩種方式
1)在類的函式__init__中,為例項繫結變數。
這也是本文討論的場景。
根據pep8,所有的加了self的變數,需要確保是在__init__中首次出現,雖然不這樣做有些場景下程式也不會出錯,但按照規定來吧。
2)在例項化後,為例項繫結新的屬性。例如,例項變數.屬性變數=值
由於Python是動態語言,從而,根據類建立的例項可以任意繫結屬性。通過例項變數給例項繫結屬性是方法之一,例如程式碼I中的,ins.newval=”I’m a new value”,為例項綁定了屬性newval。不過,這不是本文討論的關注點