【python】詳解類class的繼承、__init__初始化、super方法(五)
阿新 • • 發佈:2019-02-10
通過之前四篇的介紹:
- 【python】python中的類,物件,方法,屬性初認識(一)詳見連結
- 【python】詳解類class的屬性:類資料屬性、例項資料屬性、特殊的類屬性、屬性隱藏(二)詳見連結
- 【python】詳解類class的方法:例項方法、類方法、靜態方法(三)詳見連結
- 【python】詳解類class的訪問控制:單下劃線與雙下劃線_(四)詳見連結
Python中類相關的一些基本點已經比較完整清晰了,本文繼續深入Python中類的繼承和_ _slots _ _屬性。
1、繼承
- 在Python中,同時支援單繼承與多繼承,一般語法如下:
class SubClassName(ParentClass1 [, ParentClass2, ... ]):
class_suite
- 實現繼承之後,子類將繼承父類的屬性,也可以使用內建函式insubclass()來判斷一個類是不是另一個類的子孫類:
# -*- coding: utf-8 -*-
"""
Created on Sun Jan 21 22:33:09 2018
@author: BruceWong
"""
class Parent(object):
'''
parent class
'''
numList = []
def numdiff(self, a, b):
return a-b
class Child (Parent):
pass
c = Child()
# subclass will inherit attributes from parent class
#子類繼承父類的屬性
Child.numList.extend(range(10))
print(Child.numList)
print("77 - 2 =", c.numdiff(77, 2))
# built-in function issubclass()
print(issubclass(Child, Parent))
print(issubclass(Child, object))
# __bases__ can show all the parent classes
#bases屬性檢視父類
print('the bases are:',Child.__bases__)
# doc string will not be inherited
#doc屬性不會被繼承
print(Parent.__doc__)
print(Child.__doc__)
程式碼的輸出為:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
77 - 2 = 75
True
True
the bases are: (<class '__main__.Parent'>,)
parent class
None
例子中唯一特別的地方是文件字串。文件字串對於類,函式/方法,以及模組來說是唯一的,也就是說doc屬性是不能從父類中繼承來的。
2、繼承中的_ _init_ _
當在Python中出現繼承的情況時,一定要注意初始化函式_init_的行為:
- 如果子類沒有定義自己的初始化函式,父類的初始化函式會被預設呼叫;但是如果要例項化子類的物件,則只能傳入父類的初始化函式對應的引數,否則會出錯。
- 如果子類定義了自己的初始化函式,而在子類中沒有顯示呼叫父類的初始化函式,則父類的屬性不會被初始化
- 如果子類定義了自己的初始化函式,在子類中顯示呼叫父類,子類和父類的屬性都會被初始化
2.1、子類沒有定義自己的初始化函式,父類的初始化函式會被預設呼叫:
#定義父類:Parent
class Parent(object):
def __init__(self, name):
self.name = name
print("create an instance of:", self.__class__.__name__)
print("name attribute is:", self.name)
#定義子類Child ,繼承父類Parent
class Child(Parent):
pass
#子類例項化時,由於子類沒有初始化,此時父類的初始化函式就會預設被呼叫
#且必須傳入父類的引數name
c = Child("init Child")
子類例項化時,由於子類沒有初始化,此時父類的初始化函式就會預設被呼叫,此時傳入父類的引數name,輸出結果為:
create an instance of: Child
name attribute is: init Child
如果不傳入父類的引數name:
class Parent(object):
def __init__(self, name):
self.name = name
print("create an instance of:", self.__class__.__name__)
print("name attribute is:", self.name)
class Child(Parent):
pass
#c = Child("init Child")
#print()
c = Child()
沒有傳入父類name引數的輸出結果會報錯:
Traceback (most recent call last):
File "<ipython-input-11-9a7781a6f192>", line 1, in <module>
runfile('C:/Users/BruceWong/.spyder-py3/類的繼承.py', wdir='C:/Users/BruceWong/.spyder-py3')
File "C:\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 866, in runfile
execfile(filename, namespace)
File "C:\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 102, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "C:/Users/BruceWong/.spyder-py3/類的繼承.py", line 54, in <module>
c = Child()
TypeError: __init__() missing 1 required positional argument: 'name'
2.2、子類定義了自己的初始化函式,而在子類中沒有顯示呼叫父類的初始化函式,則父類的屬性不會被初始化
class Parent(object):
def __init__(self, name):
self.name = name
print("create an instance of:", self.__class__.__name__)
print("name attribute is:", self.name)
#子類繼承父類
class Child(Parent):
#子類中沒有顯示呼叫父類的初始化函式
def __init__(self):
print("call __init__ from Child class")
#c = Child("init Child")
#print()
#將子類例項化
c = Child()
print(c.name)
在子類中沒有顯示呼叫父類的初始化函式,則父類的屬性不會被初始化,因而此時呼叫子類中name屬性不存在:
AttributeError: ‘Child’ object has no attribute ‘name’
call __init__ from Child class
Traceback (most recent call last):
File "<ipython-input-12-9a7781a6f192>", line 1, in <module>
runfile('C:/Users/BruceWong/.spyder-py3/類的繼承.py', wdir='C:/Users/BruceWong/.spyder-py3')
File "C:\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 866, in runfile
execfile(filename, namespace)
File "C:\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 102, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "C:/Users/BruceWong/.spyder-py3/類的繼承.py", line 56, in <module>
print(c.name)
AttributeError: 'Child' object has no attribute 'name'
2.3、如果子類定義了自己的初始化函式,顯示呼叫父類,子類和父類的屬性都會被初始化
class Parent(object):
def __init__(self, name):
self.name = name
print("create an instance of:", self.__class__.__name__)
print("name attribute is:", self.name)
class Child(Parent):
def __init__(self):
print("call __init__ from Child class")
super(Child,self).__init__("data from Child") #要將子類Child和self傳遞進去
#c = Child("init Child")
#print()
d = Parent('tom')
c = Child()
print(c.name)
子類定義了自己的初始化函式,顯示呼叫父類,子類和父類的屬性都會被初始化的輸出結果:
#例項化父類Parent的結果
create an instance of: Parent
name attribute is: tom
#例項化子類Child的結果
call __init__ from Child class
#super首先會先使得父類初始化的引數進行例項化
create an instance of: Child
name attribute is: data from Child
data from Child
3、super的使用詳解
- super主要來呼叫父類方法來顯示呼叫父類,在子類中,一般會定義與父類相同的屬性(資料屬性,方法),從而來實現子類特有的行為。也就是說,子類會繼承父類的所有的屬性和方法,子類也可以覆蓋父類同名的屬性和方法。
class Parent(object):
Value = "Hi, Parent value"
def fun(self):
print("This is from Parent")
#定義子類,繼承父類
class Child(Parent):
Value = "Hi, Child value"
def ffun(self):
print("This is from Child")
c = Child()
c.fun()
c.ffun()
print(Child.Value)
輸出結果:
This is from Parent
This is from Child
Hi, Child value
但是,有時候可能需要在子類中訪問父類的一些屬性,可以通過父類名直接訪問父類的屬性,當呼叫父類的方法是,需要將”self”顯示的傳遞進去的方式:
class Parent(object):
Value = "Hi, Parent value"
def fun(self):
print("This is from Parent")
class Child(Parent):
Value = "Hi, Child value"
def fun(self):
print("This is from Child")
Parent.fun(self) #呼叫父類Parent的fun函式方法
c = Child()
c.fun()
輸出結果:
This is from Child
This is from Parent #例項化子類Child的fun函式時,首先會列印上條的語句,再次呼叫父類的fun函式方法
這種方式有一個不好的地方就是,需要經父類名硬編碼到子類中,為了解決這個問題,可以使用Python中的super關鍵字:
class Parent(object):
Value = "Hi, Parent value"
def fun(self):
print("This is from Parent")
class Child(Parent):
Value = "Hi, Child value"
def fun(self):
print("This is from Child")
#Parent.fun(self)
super(Child,self).fun() #相當於用super的方法與上一呼叫父類的語句置換
c = Child()
c.fun()
輸出結果:
This is from Child
This is from Parent #例項化子類Child的fun函式時,首先會列印上條的語句,再次呼叫父類的fun函式方法