面向?qū)ο螅∣bject Oriented Programming饼煞,簡稱OOP)中有兩個重要的概念:類(Class)和實例(Instance),類是抽象的模板诗越,而實例是根據(jù)類創(chuàng)建出來的具體“對象”砖瞧。
一、創(chuàng)建類嚷狞、對象
1块促、創(chuàng)建類
class Cat():
color = 'white'
"""貓的基本特性描述"""
def __init__(self, name, age):
"""初始化參數(shù)"""
self.name = name
self.age = age
self.sex = 'male'
def catch(self):
"""貓捉老鼠"""
print(self.name + ' is catching the mouse!')
上邊定義了一個Cat類,首先看__init__()方法(init前后各兩個下劃線)感耙,它是一個特殊方法褂乍,類似java中的構(gòu)造函數(shù),包含三個形參: self即硼、name和age逃片。其中形參self必不可少,還必須位于其他形參的前面,表示創(chuàng)建的實例本身褥实,在__init__方法內(nèi)部呀狼,就是把屬性name、age綁定到實例上的操作损离,則name哥艇、age就是實例屬性,可以通過實例訪問僻澎,其中sex是一個有默認值的實例屬性貌踏。注意color屬性綁定在類本身,屬于類屬性窟勃。
Cat類中有一個catch()方法祖乳,和普通函數(shù)類似,只多了一個必須的self參數(shù)秉氧,和init方法類似眷昆,通過類的實例調(diào)用時也不用傳遞self參數(shù)。
2汁咏、創(chuàng)建對象
創(chuàng)建Cat實例時亚斋, Python將調(diào)用Cat類的方法__init__(),參數(shù)self會自動傳遞攘滩,只需提供name帅刊、age兩個參數(shù):
>>>cat = Cat('tom', 2)
# 訪問name屬性
>>>cat.name
'tom'
# 調(diào)用catch()方法
>>>cat.catch()
tom is catching the mouse!
二、訪問屬性
前邊通過cat實例可以訪問到name屬性漂问,如果不想屬性直接被訪問厚掷,可以這樣修改Cat類:
class Cat():
def __init__(self, name, age):
self.__name = name
self.__age = age
省略了非關(guān)鍵代碼,分別在name级解、age屬性名前加了兩個下劃線__,這樣屬性就被私有化了田绑,再試著訪問一次:
>>>cat = Cat('tom', 2)
>>>cat.__name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__name'
這樣實例屬性就不能被隨意訪問修改了勤哗,代碼更加健壯。
之后要訪問name屬性掩驱,可以提供相應的發(fā)方法:
class Cat():
def __init__(self, name, age):
self.__name = name
self.__age = age
def get_name(self):
return self.__name
>>>cat = Cat('tom', 2)
>>>cat.get_name()
如果要修改屬性值芒划,可以增加相應的set方法:
class Cat():
def __init__(self, name, age):
self.__name = name
self.__age = age
def get_name(self):
return self.__name
def set_name(self, name):
return self.__name = name
>>>cat = Cat('tom', 2)
>>>cat.set_name('bob')
當然屬性前如果沒加雙下劃線,則可以直接修改屬性值:
>>>cat = Cat('tom', 2)
>>>cat.name = 'bob'
前邊提到了實例屬性和類屬性欧穴,在類屬性非私有的條件下民逼,可以直接通過實例訪問類屬性,如果存在同名的實例屬性和類屬性則實例屬性將屏蔽掉類屬性涮帘。
三拼苍、繼承
先創(chuàng)建父類Animal:
class Animal():
def __init__(self, color):
self.color= color
def slogan(self):
print('Animals are friends of human!')
再創(chuàng)建Dog子類繼承Animal:
class Dog(Animal):
def __init__(self, name, sex, color):
super().__init__(color)
self.name= name
self.sex = sex
def slogan(self):
print('Dogs are friends of human!')
def run(self):
print(self.name + ' is running!')
其中name、sex调缨、run()分別是子類的屬性和方法疮鲫。同時重寫了父類的slogan()方法吆你。
定義子類時,必須在括號內(nèi)指定父類的名稱俊犯。super()是一個特殊函數(shù)妇多,幫助Python將父類和子類關(guān)聯(lián)起來,super().__init__(name, age)
會調(diào)用
Dog的父類的方法__init__()燕侠,讓Dog的實例包含父類的所有屬性者祖。
通過繼承,子類獲得了父類的全部非私有功能:
>>>dog1 = Dog('kk', 'male', 'yellow')
>>>dog1.name
'kk'
>>>dog1.slogan()
Dogs are friends of human!
>>>dog1.run()
kk is running!
Python是支持多重繼承的绢彤!
四七问、多態(tài)
以上邊的例子為基礎(chǔ):
>>>a = Animal('white')
>>>d = Dog('kk', 'male', 'white')
>>>isinstance(a, Animal)
True
>>>isinstance(d, Dog)
True
>>>isinstance(d, Animal)
True
>>>isinstance(a, Dog)
False
用isinstance()方法可以判斷一個實例的類型。
從上邊的例子可以看出杖虾,d是Dog類型也是Animal類型烂瘫,但是a不是Dog類型。所以奇适,如果一個實例的類型是某個子類坟比,那它的類型也可以被看做是父類,但反過來就不行嚷往。這就是多態(tài)的體現(xiàn)葛账。
再看一個例子:
def show_slogan(animal):
animal.slogan()
>>>a = Animal('white')
>>>d = Dog('kk', 'male', 'white')
>>>show_slogan(a)
Animals are friends of human!
>>>show_slogan(d)
Dogs are friends of human!
什么意思呢?因為Dog是Animal的子類皮仁,都有run()方法籍琳,因此調(diào)用show_slogan()方法時只要傳入Animal類或者子類的實例,就會自動調(diào)用實際類型的run()方法贷祈。因為多態(tài)的存在趋急,新增一種Animal的子類時,只要確保run()方法編寫正確势誊,show_slogan()就可以正常執(zhí)行呜达。
五、鴨子類型
在靜態(tài)語言中粟耻,例如Java查近,如果需要傳入Animal類型,則傳入的對象必須是Animal類型或者其子類挤忙,否則將無法調(diào)用run()方法霜威。然而對于Python這樣的動態(tài)語言來說,則不一定要傳入Animal類型的對象册烈,只需保證傳入的對象有一個run()方法就可以了戈泼。
這就是動態(tài)語言的“鴨子類型”,它并不要求嚴格的繼承體系,一個對象只要“看起來像鴨子矮冬,走起路來像鴨子”谈宛,那它就可以被看做是鴨子。