字典的value爲自定義類,靜態方法與實例方法的區別及調用方式,self與__init__方法的作用
class Fun():
name = 'class_fun'
def __init__(self, speed):
self.speed = speed
@staticmethod
def display():
print('start')
car = {'brand': '奔馳','country': '德國', 'price': 3000, 'class': Fun}
這裏首先定義一個Fun類,然後創建一個字典car,其中鍵爲’class‘的一項的value爲該類名。
這裏的修飾說明這個方法是一個靜態方法,不能訪問實例屬性。注意如果希望一個方法作爲靜態方法,那麼該方法裏的“self”得去掉。實例方法不需要任何修飾。
這裏的name是一個類屬性,類屬性的特點是,它們是所有相同類型對象的共同屬性,即所有對象共用一個屬性;而實例屬性是每一個對象的特徵,每一個對象的實例屬性可以不同。
這裏的self.speed是實例屬性。實例屬性需要在初始化方法裏面定義,即__init__裏。
解釋器在執行 像fun = Fun(300)
這樣的 實例化類對象 的代碼時,首先,解釋器會 在內存中 創建一個該類 的 實例對象;然後,解釋器會查看這個類是否有 __init__方法,如果有,就會去調用它。
init 是 創建好實例後 立即就要 執行 的方法,所以稱之爲初始化方法。
通常我們會在__init__方法裏面 執行一些初始化的動作,主要就是創建該實例的 實例屬性。
init 方法的第一個參數是 self, 它 是幹什麼用的呢?
剛纔說了, 解釋器執行實例化代碼,會先在內存中創建該類實例對象,然後調用類 的__init__方法。
調用 __init__方法時,就將實例對象 傳遞給 self參數。self 參數 需要傳入實例對象本身,解釋器會自動幫我們傳入,不需要我們手動傳入。
self 參數變量 指向的 就是 實例對象 本身,所以,self.speed = speed
就是創建該實例的屬性speed了。下面進行一些輸出測試:
輸入:
# 這裏沒有創建一個實例
print(car['class'].name)
# 這裏首先創建一個實例,然後調用display靜態方法
print(car['class'](100).display())
輸出:
'class_fun'
start
對於靜態方法,可以不用像上面那樣先定義一個實例然後再調用,可以直接使用類名調用
輸入:
print(car['class'].display())
輸出:
start
如果將該靜態方法改成實例方法,首先將方法括號裏的self去掉,其實去掉之後上面的裝飾器就起不到作用了,爲了避免造成誤解最好也把裝飾器去掉,然後試試直接使用類名調用實例方法:
輸入:
print(car['class'].display())
輸出:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-9-524169c831e9> in <module>()
----> 1 car['class'].display()
TypeError: display() missing 1 required positional argument: 'self'
報錯。想要調用實例方法,得先創建一個實例。
類的繼承
繼承類的時候首先要在子類中傳入父類,然後再在子類的初始化方法裏調用父類的初始化方法。
其中調用父類的初始化方法有三種常用的方式:
方式1:
class Fun():
name = 'class_fun'
def __init__(self, speed):
self.speed = speed
@staticmethod
def display():
print('start')
class FunSon(Fun):
def __init__(self, speed, color):
super(FunSon, self).__init__(speed)
self.color = color
方式2:
class Fun():
name = 'class_fun'
def __init__(self, speed):
self.speed = speed
@staticmethod
def display():
print('start')
class FunSon(Fun):
def __init__(self, speed, color):
Fun.__init__(self, speed)
self.color = color
方式3:
class Fun():
name = 'class_fun'
def __init__(self, speed):
self.speed = speed
@staticmethod
def display():
print('start')
class FunSon(Fun):
def __init__(self, speed, color):
super().__init__(speed)
self.color = color
其中幾種方式都要注意的是,在子類的初始化方法的後面參數列表裏需要將父類的實例屬性全部寫進去,然後再加上子類自己獨有的實例屬性。
使用super的好處之一就是:子類中調用父類的方法,不需要 顯式指定 父類的名字。 代碼的可維護性更好。
想象一下,如果Fun有很多子類,如果Fun類改了名字,採用super這樣的寫法,就不需要修改子類的代碼了。
注意 super不僅僅可以調用父類的初始化方法,也可以調用父類的其他方法。
當然,如果子類 沒有 自己的初始化方法,實例化子類對象時,解釋器會自動調用父類初始化方法,比如下面的情況:
class Fun():
name = 'class_fun'
def __init__(self, speed):
self.speed = speed
@staticmethod
def display():
print('start')
class FunSon(Fun):
pass
類中的__repr__方法
car = FunSon(100,'red')
print(car)
輸出:
<__main__.FunSon object at 0x7fb622f98860>
輸出的是實例對象car儲存的位置。但是如果希望輸出一些car的基本信息呢?需要定義__repr__方法:
def __repr__(self):
return f'speed = {self.speed}, color = {self.color}'
print(car)
speed = 100, color = red