目錄
1、self的作用
self
指的是呼叫該函式的物件(是一個例項)。Python中self
等價於Java中的this
。
首先明確的是self
只有在類中的方法中才會有,獨立的函式或方法是不必帶有self
的。
例如:
# 定義方法
def showTime(name):
print(f'大家好我是{name},多多關照!')
# 呼叫方法
showTime('齊天大聖')
"""
輸出結果:
大家好我是齊天大聖,多多關照!
"""
2、self的使用注意事項
(1)self代表類的例項,而非類
# self代表類的例項,而非類
class TestDemo():
# 可將self理解為例項td
def testFn(self):
print(f"誰呼叫我,我就是誰,此時呼叫我的是{self}")
# 例項呼叫__class__屬性時會指向該例項對應的類
print(f"我是按照{self.__class__}建立出來的")
# td為TestDemo的例項
td = TestDemo()
# 在類中方法的形參中,self引數一定要定義,但是在呼叫時會自動傳入。
td.testFn()
執行結果如下:
誰呼叫我,我就是誰,此時呼叫我的是<__main__.TestDemo object at 0x00000000028836C8>
我是按照<class '__main__.TestDemo'>建立出來的
說明:
<__main__.TestDemo object at 0x00000000028836C8>
表示:
self
是一個TestDemo
型別的object
(物件),物件在記憶體的地址為0x00000000028836C8
。
為什麼self
指的是類的例項物件,而不是類本身。
如果self
指向類本身,那麼當一個類有多個例項物件時,self
指向哪一個呢?
(2)self不必非寫成self,只是一種規範。
有很多人先學習別的語言,如Java,然後再學習Python的,所以總覺得self
怪怪的,想寫成this
,可以嗎?
當然可以,換成任何識別符號都可以,把上面的程式碼改寫一下。
# self代表類的例項,而非類
class TestDemo():
# 可將self理解為例項td
def testFn(this):
print(f"誰呼叫我,我就是誰,此時呼叫我的是{this}")
# 例項呼叫__class__屬性時會指向該例項對應的類
print(f"我是按照{this.__class__}建立出來的")
# td為TestDemo的例項
td = TestDemo()
# 在類中方法的形參中,self引數一定要定義,但是在呼叫時會自動傳入。
td.testFn()
執行結果如下:
誰呼叫我,我就是誰,此時呼叫我的是<__main__.TestDemo object at 0x00000000028836C8>
我是按照<class '__main__.TestDemo'>建立出來的
改成this
後,執行結果完全一樣。
當然,最好還是尊重約定俗成的習慣,使用self
。(不是最好,是一定。)
(3)類中方法的形參中一定要寫self,包括內建函式
# 如果類中的方法不寫self形參,
# 則不能使用物件.方法名()來呼叫方法,
# 只能使用類名.方法名()的方式來呼叫該方法,
# 類似與Java中的靜態方法。
class TestDemo():
# 定義一個方法,不定義self形參
def testFn():
print(f"不定義形參self,依舊可以呼叫我")
print(__class__)
# 建立物件,用物件.方法名()來呼叫方法
td = TestDemo()
# 報錯
# TypeError: testFn() takes 0 positional arguments but 1 was given
td.testFn()
# 只能使用類名.方法名()的方式來呼叫該方法。
TestDemo.testFn()
(4)__init__
函式中,要把接收到的引數賦值到self中,提供全類使用
關於__init__
函式,可以檢視類的內建函式來了解。
class Student():
def __init__(self, name, age, addr):
# self的作用主要表示這個變數是類中的公共變數
# 定義在self中的屬性,整個類內都可以使用
# 普通方法同理
self.name = name
self.age = age
# 沒有定義在self中的屬性,只能在當前方法內使用
addr = addr
# 標準用法
def tellMeName(self):
# 如果去掉此處的self,會提示name 'name' is not defined
print(f'我不叫孫悟空,我叫{self.name}')
# 方法形參沒有定義self,則報錯
# TypeError: tellMeAge() takes 0 positional arguments but 1 was given
# def tellMeAge():
def tellMeAge(self):
# 如果獲取age的值不加self,則獲取不到,會報錯
# NameError: name 'age' is not defined
# print(f'我今年{age}啦')
print(f'我今年{self.age}啦')
def tellMeAddr(self):
# 因為__init__函式彙總沒有把addr變數定義在self物件中
# 所以addr變數的作用域只在__init__函式內,
# 其他函式無法呼叫。
# 新增在self物件內的屬性為全域性屬性。
print(f'我現居住在{self.addr}')
s = Student('美猴王', 18, addr='北京')
s.tellMeName()
s.tellMeAge()
s.tellMeAddr()
(5)同一個類中呼叫其他的方法時需要加self
class Student():
def __init__(self, name, age, addr):
# self的作用主要表示這個變數是類中的公共變數
# 定義在self中的屬性,整個類內都可以使用
# 普通方法同理
self.name = name
self.age = age
self.addr = addr
def tellMeName(self):
print(f'我不叫孫悟空,我叫{self.name}')
def tellMeAge(self):
print(f'我今年{self.age}啦')
def tellMeAddr(self):
print(f'我現居住在{self.addr}')
def tellAll(self):
# 如果呼叫類中的其他函式時,不用self呼叫,則會報錯
# NameError: name 'tellMeName' is not defined
# tellMeName()
self.tellMeName()
self.tellMeAge()
self.tellMeAddr()
s = Student('美猴王', 18, addr='北京')
s.tellAll()
"""
輸出結果:
我不叫孫悟空,我叫美猴王
我今年18啦
我現居住在北京
"""
(6)self總是指呼叫時的類的例項,在繼承時中也一樣
# 定義一個父類
class Parent():
def pFn(self):
print(self)
# 定義一個子類
class Child(Parent):
def cFn(self):
print(self)
# 建立子類物件
child = Child()
# 呼叫子類方法
# <__main__.Child object at 0x00000000025A38C8>
child.cFn()
# 子類呼叫父類方法
# <__main__.Child object at 0x00000000025A38C8>
child.pFn()
# 建立父類
parent = Parent()
# 呼叫自己方法
# <__main__.Parent object at 0x00000000025A3908>
parent.pFn()
(7)self與私有變數的用法
# self的屬性名稱前加上兩個下劃線,就變成了一個私有變數(private)
# 只有類內部可以訪問,外部不能直接訪問
class Student():
def setname(self, name1, name2):
self.name1 = name1
self.__name2 = name2
def getname(self):
print(f'我的第一個名字是{self.name1},我的第二個名字是{self.__name2}')
stu = Student()
stu .setname("齊天大聖", "美猴王")
# 結果:我的第一個名字是齊天大聖,我的第二個名字是美猴王
stu .getname()
# 結果:齊天大聖
print(stu.name1)
# 結果報錯:AttributeError: 'Student' object has no attribute 'name2'
# 說明私有變數並不能獲取到
print(stu.name2)
(8)總結
self
總是指呼叫時的類的例項。self
的名字並不是規定死的,但是在Python中self
不是關鍵詞,你可以定義成this
、abc
或其它名字都可以。但是約定成俗,減少程式碼理解難度。- 在類中方法的形參中,
self
引數一定要定義,但是在呼叫時會自動傳入。
(9)綜合練習
一個類可以建立多個物件。
# 需求:洗衣機,功能:能洗衣服
# 1. 定義洗衣機類
class Washer():
def wash(self):
print('我會洗衣服')
print(self)
# 2. 建立物件
haier1 = Washer()
# <__main__.Washer object at 0x0000000002553508>
print(haier1)
# haier1物件呼叫例項方法(物件方法)
haier1.wash()
# 3.建立第二個物件
haier2 = Washer()
# <__main__.Washer object at 0x0000000002553608>
print(haier2)
haier2.wash()
"""
輸出結果:
<__main__.Washer object at 0x00000000025A3688>
我會洗衣服
<__main__.Washer object at 0x00000000025A3688>
<__main__.Washer object at 0x00000000025A3788>
我會洗衣服
<__main__.Washer object at 0x00000000025A3788>
"""
"""
可以看到每建立一個新的物件,都是有獨立空間的物件,
所以每個物件的地址是不同的。
"""
注意:
可以看到每建立一個新的物件,都是有獨立空間的物件,因為每個物件的地址是不同的。
每次列印物件和
self
得到的結果是一致的,說明self
指向了物件的例項。