類與對象
把類的個例就叫做實例 (instance),可理解為“實際的例子”
類是某個特定的群體,實例是群體中某個具體的個體
Python中的對象等於類和實例的集合:即類可以看作是對象,實例也可以看作是對象,
比如列表list是個類對象,[1,2]是個實例對象,它們都是對象
“萬事萬物,皆為對象”
類的創建和調用
類的創建
類名的首字母要大寫
1 class Chinese: # 創建一個類 2 eye = 'black' 3 4 def eat(self): #參數self的特殊之處:在定義時不能丟,在調用時要忽略 5 print('吃飯,選擇用筷子。') 6 7 wu = Chinese() # 類的實例化 8 print(wu.eye) # 實例調用類屬性 9 wu.eat() # 調用類中的方法(傳參不用管self)
print(type(wu))
<class '__main__.Chinese'> #驗證了wufeng屬於Chinese這個類
print(wu)
<__main__.Chinese object at 0x7f295682d400> #Chinese類的一個實例對象(object),后面的一串字符表示這個對象的內存地址
#類中創建的屬性和方法可以被其所有的實例調用,
而且,實例的數目在理論上是無限的。
我們可以同時“新建”多個實例
類也被稱為“實例工廠”,因其為所有實例提供了一套藍圖(即預先設定好有什么屬性和方法)
創建類的兩個關鍵點
一 。特殊參數:self
那么如果想在類的內部調用類屬性,而實例又還沒創建之前,我們就需要有個變量先代替實例接收數據,這個變量就是參數self。
1 class Chinese: 2 3 name = '吳' # 類屬性name 4 5 def say(self): 6 print(self.name + '是中國人') 7 8 person = Chinese() # 創建Chinese的實例person 9 person.say() # 調用實例方法
當最后一行代碼運行時,實例person會像參數一樣傳給self,替換掉self,self.name等價於person.name
person.name就相當於調用了類屬性name(即'吳'),然后跑完整個方法
相當於以下:
1 class Chinese: 2 3 name = '吳' # 類屬性name 4 5 def say(person): 6 print(person.name + '是中國人') 7 8 person = Chinese() # 創建Chinese的實例person 9 person.say() # 調用實例方法 10 吳是中國人
如果想在類的方法內部調用其他方法時,我們也需要用到self來代表實例
1 class Chinese: 2 3 def greeting(self): 4 print('很高興遇見你') 5 6 def say(self): 7 self.greeting() 8 print('我來自中國') 9 10 person = Chinese() # 創建實例person 11 12 person.say() # 調用say()方法 13 很高興遇見你 14 我來自中國
self代表的是類的實例本身,方便數據的流轉
對此,我們需要記住兩點
第一點:只要在類中用def創建方法時,就必須把第一個參數位置留給 self,並在調用方法時忽略它(不用給self傳參)。
第二點:當在類的方法內部想調用類屬性或其他方法時,就要采用self.屬性名或self.方法名的格式。
##############################################################################################
二。特殊方法:初始化方法 (也叫構造函數)
定義初始化方法的格式是def __init__(self),是由init加左右兩邊的【雙】下划線組成
初始化方法的作用在於:當每個實例對象創建時,該方法內的代碼無須調用就會自動運行。
1 class Chinese: 2 3 def __init__(self): 4 print('很高興遇見你,我是初始化方法') 5 6 person = Chinese() 7 很高興遇見你,我是初始化方法
編寫習慣上,我們會在初始化方法內部完成類屬性的創建,為類屬性設置初始值,
這樣類中的其他方法就能直接、隨時調用
1 class Chinese: 2 def __init__ (self): 3 self.mouth = 1 # self.不能丟 4 self.eye = 2 5 6 def body(self): 7 print('我有%s張嘴巴' % self.mouth) 8 print('我有%s只眼睛' % self.eye) 9 10 person = Chinese() 11 person.body() 12 我有1張嘴巴 13 我有2只眼睛
除了設置固定常量,初始化方法同樣可以接收其他參數
1 class Chinese: 2 3 def __init__(self, name, birth, region): 4 self.name = name # self.name = '吳' 5 self.birth = birth # self.birth = '廣東' 6 self.region = region # self.region = '深圳' 7 8 def born(self): 9 print(self.name + '出生在' + self.birth) 10 11 def live(self): 12 print(self.name + '居住在' + self.region) 13 14 person = Chinese('吳','廣東','深圳') # 傳入初始化方法的參數 15 #初始化方法有多個參數的時候,在實例化的時候就要傳入相應的值 16 person.born() 17 person.live() 18 吳出生在廣東 19 吳居住在深圳
#其實還可以不用初始化方法也能實現
但是此方法比不上初始化方法
初始化優點:
至少不必重復傳參,傳入的數據還可以被多次調用
1 class Chinese: 2 3 def born(self, name, birthplace): 4 print(name + '出生在' + birthplace) 5 6 def live(self, name, region): 7 print(name + '居住在' + region) #不建議用此方法 8 9 person = Chinese() 10 person.born('吳','廣東') 11 person.live('吳','深圳')
一次性調用
1 class Chinese: 2 def __init__(self,hometown,region): 3 self.hometown = hometown 4 self.region = region 5 print('程序持續更新中……') 6 7 def born(self): 8 print('我生在%s。'%(self.hometown)) 9 10 def live(self): 11 print('我在%s。'%(self.region)) 12 13 # 新建方法,調用上面的兩個方法(注:方法名可自定義)。 14 def citys(self): 15 self.born() 16 self.live() 17 18 wu = Chinese('廣東', '深圳') 19 wu.citys() 20 # 調用方法后,程序運行方法中的代碼(即依次調用方法`born`和`live`)。 21 程序持續更新中…… 22 我生在廣東。 23 我在深圳。
#####################################################################################################
面向對象編程
與面向對象編程相對應的是面向過程編程
面向過程編程:首先分析出解決問題所需要的步驟(即“第一步做什么,第二步做什么,第三步做什么”),
然后用函數實現各個步驟,再依次調用。
面向對象編程,將代碼具體的數據和處理方法都封裝在類中,讓我們不用完全了解過程也可以調用類中的各種方法。
這個優勢讓我們可以在 Python 中輕松地調用各種標准庫、第三方庫和自定義模塊(可以簡單理解成別人寫好的類)
#類編寫一個直觀的好處就是參數的傳遞會比普通函數要省事很多,也不必考慮全局變量和局部變量,因為類中的方法可以直接調用屬性。
#####################################################################################################################
綜合例子
1 class Robot: 2 def __init__(self): 3 self.name = input('我現在剛誕生,還沒有名字,幫我起一個吧。') 4 self.master = input('對了,我要怎么稱呼你呢?') 5 print('你好%s,我叫%s。很開心,遇見你~'%(self.master,self.name)) 6 7 def say_wish(self): 8 wish = input('告訴我一個你的願望吧:') 9 print(self.master+'的願望是:') 10 # 這里也可以用字符串的格式化,不過,用循環語句的話,之后改復述次數會方便些。 11 for i in range(3): 12 print(wish) 13 14 robot1 = Robot() 15 robot1.say_wish()
#############################################################################################################################
類的繼承和定制
A類屬於B類,自然也擁有了B類的所有屬性和方法。
這句話在編程里就是:A類繼承了B類。
Python中,我們的習慣表述是:A類是B類的子類,而B類是A類的父類(或超類)
定制
子類也可以在繼承的基礎上進行個性化的定制
(1)創建新屬性、新方法;
(2)修改繼承到的屬性或方法。
————————————————————————————————————————————
繼承的基礎語法
class Chinese:在運行時相當於class Chinese(object):。
而object,是所有類的父類,我們將其稱為根類(可理解為類的始祖)。
1 #函數isinstance(),判斷某個實例是否屬於某個類 2 print(isinstance(1,int)) ## 判斷1是否為整數類的實例 3 True 4 print(isinstance(1,str)) 5 False 6 print(isinstance(1,(int,str))) # 判斷實例是否屬於元組里幾個類中的一個 7 True
1 class Chinese: 2 pass 3 4 class Cantonese(Chinese): 5 pass 6 7 gonger = Chinese() 8 yewen = Cantonese() 9 10 print('\n驗證1:子類創建的實例同時也屬於父類') 11 print(isinstance(gonger,Chinese)) 12 print(isinstance(yewen,Chinese)) 13 14 print('\n驗證2:父類創建的實例不屬於子類。') 15 print(isinstance(gonger,Cantonese)) 16 17 print('\n驗證3:類創建的實例都屬於根類。') 18 print(isinstance(gonger,object)) 19 print(isinstance(yewen,object)) 20 21 驗證1:子類創建的實例同時也屬於父類 22 True 23 True 24 25 驗證2:父類創建的實例不屬於子類。 26 False 27 28 驗證3:類創建的實例都屬於根類。 29 True 30 True
————————————————————————————————————————————
類的繼承之多層繼承
子類創建的實例可調用所有層級父類的屬性和方法
1 class Earthman: 2 eye_number = 2 3 4 # 中國人繼承了地球人 5 class Chinese(Earthman): 6 eye_color = 'black' 7 8 # 廣東人繼承了中國人,同時也繼承了地球人。 9 class Cantonese(Chinese): 10 pass 11 12 yewen = Cantonese() 13 print(yewen.eye_number) 14 print(yewen.eye_color) 15 2 16 black
####################################################################
類的繼承之多重繼承
一個類,可以同時繼承多個類,
語法為 class A(B,C,D):
就近原則:
越靠近子類(即越靠左)的父類,越親近,越優先考慮。子類調用屬性和方法時,會先在靠左的父類里找,找不到才往右找。
1 class Su: 2 born_city = 'Jiangsu' 3 wearing = 'thick' 4 5 def diet(self): 6 print('我們愛吃甜。') 7 8 class Yue: 9 settle_city = 'Guangdong' 10 wearing = 'thin' 11 12 def diet(self): 13 print('我們吃得清淡。') 14 15 class Yuesu(Yue,Su): 16 pass 17 18 xiaoming = Yuesu() 19 print(xiaoming.wearing) # 先在 Yue類找,找到了,打印出來。 20 print(xiaoming.born_city) # Yue類沒有born_city,才去Su類找。 21 xiaoming.diet() # 方法調用,和屬性調用一樣,也符合就近原則。 22 23 thin 24 Jiangsu 25 我們吃得清淡。
類的定制
定制,可以新增代碼
1 class Chinese: 2 eye = 'black' 3 4 def eat(self): 5 print('吃飯,選擇用筷子。') 6 7 class Cantonese(Chinese): # 類的繼承 8 native_place = 'guangdong' # 類的定制 9 10 def dialect(self): # 類的定制 11 print('我們會講廣東話。') 12 13 yewen = Cantonese() 14 print(yewen.eye) # 父類的屬性能用 15 print(yewen.native_place) # 子類的定制屬性也能用 16 yewen.eat() # 父類的方法能用 17 yewen.dialect() # 子類的定制方法也能用 18 19 black 20 guangdong 21 吃飯,選擇用筷子。 22 我們會講廣東話。
定制,也可重寫代碼
在子類中,對父類代碼的修改
子類繼承父類方法的操作是在def語句后接父類.方法(參數)
1 class Chinese: 2 3 def land_area(self,area): 4 print('我們居住的地方,陸地面積是%d萬平方公里左右。'% area) 5 6 class Cantonese(Chinese): 7 # 間接對方法進行重寫 8 def land_area(self, area, rate = 0.0188): 9 Chinese.land_area(self, area * rate) 10 # 直接繼承父類方法,再調整參數。 11 12 gonger = Chinese() 13 yewen = Cantonese() 14 gonger.land_area(960) 15 yewen.land_area(960)
提示:初始化方法的定制,和一般的實例方法的定制是一樣的。
1 class Chinese: 2 def __init__(self, greeting='你好', place='中國'): 3 self.greeting = greeting 4 self.place = place 5 6 def greet(self): 7 print('%s!歡迎來到%s。' % (self.greeting, self.place)) 8 9 # 請為子類完成定制,代碼量:兩行。 10 class Cantonese(Chinese): 11 def __init__(self, greeting='雷猴', place='廣東'): #重寫代碼最好是在繼承方法的基礎上通過代碼的調整完成定制 12 Chinese.__init__(self, greeting ,place) 13 14 yewen = Cantonese() 15 yewen.greet() 16 雷猴!歡迎來到廣東。
###################################################################################################################
列子
1 class Student: 2 def __init__(self, name, job=None, time=0.00, time_effective=0.00): 3 self.name = name 4 self.job = job 5 self.time = time 6 self.time_effective = time_effective 7 8 def count_time(self, hour, rate): 9 self.time += hour 10 self.time_effective += hour * rate 11 12 class Programmer(Student): 13 def __init__(self, name): #此處為啥只留name參數,因為沒有給出默認值,需要傳入參數,不能省略,然后其他都是默認參數 14 Student.__init__(self, name, job='programmer', time=0.00, time_effective=0.00) 15 16 def count_time(self, hour, rate=1): 17 Student.count_time(self, hour, rate) 18 19 student1 = Student('韓梅梅') 20 student2 = Programmer('李雷') 21 22 print(student1.job) 23 print(student2.job) 24 25 student1.count_time(10, 0.8) 26 student2.count_time(10) 27 28 print(student1.time_effective) 29 print(student2.time_effective)