Python面向對象的編程

1概述

(1)面向對象編程

??面向對象的編程是利用“類”和“對象”來創建各種模型來實現對真實世界的描述,使用面向對象編程的原因一方面是因為它可以使程序的維護和擴展變得更簡單,并且可以大大提高程序開發效率,另外,基于面向對象的程序可以使它人更加容易理解你的代碼邏輯,從而使團隊開發變得更從容。

(2)面向對象的特征

? ?1)類(Class):一個類即是對一類擁有相同屬性的對象的抽象、藍圖、原型。在類中定義了這些對象的都具備的屬性(variables(data))、共同的方法

? ?2)對象(Object)?:一個對象即是一個類的實例化后實例,一個類必須經過實例化后方可在程序中調用,一個類可以實例化多個對象,每個對象亦可以有不同的屬性,就像人類是指所有人,每個人是指具體的對象,人與人之前有共性,亦有不同

? ?3)封裝(Encapsulation):在類中對數據的賦值、內部調用對外部用戶是透明的,這使類變成了一個膠囊或容器,里面包含著類的數據和方法

? ?4)繼承(Inheritance):一個類可以派生出子類,在這個父類里定義的屬性、方法自動被子類繼承

? ?5)多態(Polymorphism):多態是面向對象的重要特性,簡單點說:“一個接口,多種實現”,指一個基類中派生出了不同的子類,且每個子類在繼承了同樣的方法名的同時又對父類的方法做了不同的實現,這就是同一種事物表現出的多種形態。

(3)簡單用法

class?People(object):????#創建一個類,類名首字母要大寫,并繼承object類def?walk(self):print?"i?am?walking..."def?talk(self):print?"talking?with?sb..."p1?=?People()???#創建一個對象,屬于People類
p1.walk()????????#調用walk方法
p1.talk()p2?=?People()
p2.walk()
p2.talk()

2類的方法

(1)類的方法及屬性

? ?1)類的方法——self

? ?類的方法(類函數)與普通的函數只有一個特別的區別——它們必須有一個額外的第一個參數名稱,但是在調用這個方法的時候你不為這個參數賦值,Python會提供這個值。這個特別的變量指對象本身,按照慣例它的名稱是self。

??如你有一個類稱為MyClass和這個類的一個實例MyObject。當你調用這個對象的方法MyObject.method(arg1, arg2)的時候,這會由Python自動轉為MyClass.method(MyObject, arg1, arg2)

? ?2)__init__()初始化

? ?作用:對實體進行初始化

? ?如:classDog:

? ? ? def__init__(self,name):

? ? ? self.DogName= name #必須賦值self,否則類中其它函數無法調用

(3)類的方法舉例:

class?People(object):info=?'test'??#共享變量,如果實例變量中找不到時,會找共享變量def?__init__(self,name,age,job):?#構造函數(實例化函數)self.name?=?name?#變成實例變量,即將類的局部變量變為類的全局變量self.age?=?ageself.job?=?job#self.info?=?'t2'??#改變info的值def?walk(self):print?"i?am?walking..."def?talk(self):print?"talking?with?sb...",People.infop1?=?People("Dayi",22,"it")
p2?=?People("liuyi",24,"itman")
p3?=?People("t3",18,"ll")p1.info?=?"P1"
print?'P1:',p1.info
People.info?=?"haha"???????#如果構造函數中修改了info的值,則此處再無法修改
print?'p2:',p2.info
print?'p3:',p3.info

(4)析構函數

??在實例釋放、銷毀的時候自動執行的,通常用于做一些收尾工作,如關閉一些數據庫連接,關閉打開的臨時文件。

#!/usr/bin/env?python
class?Create_role:def?__init__(self,name,age,job):self.name=?nameself.age?=ageself.job?=jobdef?show(self):print("Name:%s?Age:%s?Job:%s"%(self.name,self.age,self.job))def?__del__(self):??#定義一個析構方法print("%s?已經徹底清理了"?%(self.name)?)r1?=?Create_role("Dayi",18,"it")
print(r1.name)
r1.show()
del?r1???#在r1調用結束后,立即執行析構方法,默認在程序執行完成之后才會執行
r2?=?Create_role("xiaoliu",23,"no")
r2.show()
r3?=?Create_role("hehe",30,"bois")

(5)類的私有屬性及私有方法(類的封裝)

? ?python默認的成員函數和成員變量都是公開的。在python中定義私有變量只需要在變量名或函數名前加上 "__"兩個下劃線,那么這個函數或變量就會為私有的了。在內部,將 __membername替換成 _classname__membername后,你在外部使用原來的私有成員的名字時,會提示找不到,但是可以在內部調用。

class?People(object):info?=?'test'??#共享變量def?__init__(self,name,age,job):?#構造函數(實例化函數)self.name?=?name?#變成實例變量,即將類的局部變量變為類的全局變量self.__age?=?age??#定義一個私有屬性,方法為在屬性名前加__self.job?=?jobself.info?=?'t2'??#改變info的值self.info_dic?=?{"name":'day',"age":"33"}def?get_info(self,info_type):if?info_type?==?'age':return?self.__ageelif?info_type?==?'job':return?self.jobdef?__breath(self):????#定義一個私有方法,只能在內部調用,創建方法為函數名前加__print("%s?is?breathing..."?%self.name)def?walk(self):print?"i?am?walking..."print(self.__breath())???????#在內部調用私有方法def?talk(self):print("talking?with?sb...",People.info)p1?=?People("Dayi",22,"it")
p2?=?People("liuyi",24,"itman")p1.walk()
print(p1.get_info("age"))
print(p1._People__age)???#調用只讀屬性

3類的的繼承

? ?Python中類可以承繼父類屬性,也可以同時繼承多個父類;形式為class 類名(父類1,父類2),子類可以繼承父類的所有方法和屬性,也可以重載父類的成員函數及屬性,須注意的是子類成員函數若重載父類(即名字相同),則會使用子類成員函數

(1)類的基本繼承

class?SchoolMember(object):def?__init__(self,name,age,sex):?#創建父類構造函數self.name?=?nameself.age?=?ageself.sex?=?sexdef?tell(self):????#父類創建一個方法print('''--info?of?%s--name:%sage?:%ssex?:%s'''%(self.name,self.name,self.age,self.sex))class?Student(SchoolMember):????#創建一個類,并繼承SchoolMemberdef?__init__(self,name,age,sex,grade):???#創建子類繼承函數SchoolMember.__init__(self,name,age,sex)???#讓子類的構造函數繼承父類self.grade?=?gradedef?pay_money(self):???????#給子類創建一個方法print("---%s?is?paying?the?tuition?fee---"?%?self.name)def?tell(self):SchoolMember.tell(self)????#讓子類的tell()方法繼承父類print("---from?%s"?%?self.grade)
class?Teacher(SchoolMember):def?__init__(self,name,age,sex,course,salary):SchoolMember.__init__(self,name,age,sex)self.course?=?courseself.salary?=?salarydef?teaching(self):print("Teacher?%s?is?teaching?class?of?%s"?%(self.name,self.course))s?=?Student("dayi",33,"M","py?s10")
t?=?Teacher("liu",18,"M","python",?60000)
s.tell()
t.tell()
s.pay_money()
t.teaching()

(2)類的多繼承

? ?1)繼承一:

class?SchoolMember(object):def?__init__(self,name,age,sex):?#創建父類構造函數self.name?=?nameself.age?=?ageself.sex?=?sexdef?tell(self):????#父類創建一個方法print?'''--info?of?%s--name:%sage?:%ssex?:%s'''%(self.name,self.name,self.age,self.sex)
class?School(object):def?__init__(self,name,addr,tel):?#再創建一個父類構造函數self.school_name?=?nameself.addr?=?addrself.tel?=?telself.stu_list?=?[]self.tech_list?=?[]
class?Student(SchoolMember,School):????#創建一個類,并繼承SchoolMember和School兩個類def?__init__(self,name,age,sex,grade):???#創建子類繼承函數SchoolMember.__init__(self,name,age,sex)???#讓子類的構造函數繼承父類School.__init__(self,"beida","shahe",999)?#讓子類的構造函數繼承父類并給傳遞參數self.grade?=?gradedef?pay_money(self):???????#給子類創建一個方法print?"---%s?is?paying?the?tuition?fee---"?%?self.namedef?tell(self):SchoolMember.tell(self)????#讓子類的tell()方法繼承父類print?'''---from?school?name?:%sclass?:%saddr??:%s'''%(self.school_name,self.grade,self.addr)s?=?Student("dayi",33,"M","py?s10")
s.tell()
s.pay_money()

2)繼承二(通過super):

class?School(object):def?__init__(self,name,addr):self.name=?nameself.addr=?addrself.students?=[]self.staffs=[]def?enroll(self,stu_obj):print("為學員%s?辦理注冊手續"%stu_obj.name?)self.students.append(stu_obj)def?hire(self,staff_obj):self.staffs.append(staff_obj)print("雇傭新員工%s"?%?staff_obj.name)class?SchoolMember(object):def?__init__(self,name,age,sex):self.name=?nameself.age?=ageself.sex?=sexdef?tell(self):passclass?Teacher(SchoolMember):def?__init__(self,name,age,sex,salary,course):super(Teacher,self).__init__(name,age,sex)self.salary=?salaryself.course=?coursedef?tell(self):print('''----?info?of?Teacher:%s?----Name:%sAge:%sSex:%sSalary:%sCourse:%s'''%(self.name,self.name,self.age,self.sex,self.salary,self.course))def?teach(self):print("%s?is?teaching?course?[%s]"?%(self.name,self.course))class?Student(SchoolMember):def?__init__(self,name,age,sex,stu_id,grade):super(Student,self).__init__(name,age,sex)self.stu_id=?stu_idself.grade=?gradedef?tell(self):print('''----?info?of?Student:%s?----Name:%sAge:%sSex:%sStu_id:%sGrade:%s'''?%?(self.name,?self.name,self.age,?self.sex,?self.stu_id,self.grade))def?pay_tuition(self,amount):print("%s?has?paid?tution?for?$%s"%?(self.name,amount)?)school?=?School("qinghua","海淀")???#為School對象創建一個類t1?=?Teacher("day",56,"MF",200000,"Linux")
t2?=?Teacher("liu",22,"M",3000,"PythonDevOps")s1?=?Student("dayi123",36,"MF",1001,"PythonDevOps")
s2?=?Student("hehe",19,"M",1002,"Linux")t1.tell()????#調用Teacher類的tell()方法
s1.tell()
school.hire(t1)
school.enroll(s1)
school.enroll(s2)print(school.students)
print(school.staffs)
school.staffs[0].teach()#獲取staffs列表中的第一個元素,并調用Teacher類中的teach方法
#school.students[0].pay_tuition(2000)?for?stu?in?school.students:?????#循環School類中的student列表的元素并賦值給stustu.pay_tuition(5000)???????#調用School中的pay_tuition()方法,并傳一個參數

(3)繼承總結

? ?py2 經典類是按深度優先來繼承的,新式類是按廣度優先來繼承的

? ?py3 經典類和新式類都是統一按廣度優先來繼承的

4、多態(一個接口、多種實現):

??多態意味著就算不知道變量所應用的對象類型是什么,還是能對他進行操作,而它也回根據對象(或類)類型的不同而表現出不同的行為。

class?Animal:def?__init__(self,name):??#?Constructor?of?the?classself.name=?namedef?talk(self):??#Abstract?method,?defined?by?convention?onlypass?#raiseNotImplementedError("Subclass?must?implement?abstract?method")@staticmethoddef?animal_talk(obj):???#將調用方法封裝在父類中obj.talk()class?Cat(Animal):def?talk(self):print('%s?:Meow!'%self.name)class?Dog(Animal):def?talk(self):print('%s:?Woof!?Woof!'%self.name)d?=?Dog("我c")
#d.talk()c?=?Cat("小貓貓")
#c.talk()
#
#?def?animal_talk(obj):
#?????obj.talk()Animal.animal_talk(c)????#調用c對象
Animal.animal_talk(d)

5、靜態方法和類方法

(1)靜態方法:類的靜態方法名義上歸類管理,實際上在靜態方法里訪問不了類或實例中的任何屬性,靜態方法在創建時被裝入staticmethod類型的對象中。靜態方法創建時沒有self參數,且能夠被類本身直接調用。

(2)類方法:類方法創建時被裝入classmethod類型的對象中,類方法可以直接用類的具體對象調用,但類方法只能訪問類變量,不能訪問類的實例變量。

(3)屬性方法:類的屬性方法可以把一個類的方法變成一個類的靜態屬性。

class?MyClass(object):age?=?22def?__init__(self):self.name=?"hehele"def?sayhi(self):#必須實例化才能調用print("---sayhi?1")@staticmethoddef?sayhi2():#靜態方法,跟類沒甚么關系,不需要實例化即可調用,類的工具包print("---sayhi?2")@staticmethoddef?sayhi2_2(self):#靜態方法,如果實在想傳參了,可以這樣搞print("---sayhi?2",self.name)@classmethoddef?sayhi3(self):#不需要實例化即可調用,不能訪問實例數據,?訪問了實例化中的數據(self.name)調用時會報錯。print("---sayhi?3",self.age,self.name)@property#將函數變成靜態屬性def?sayhi4(self):print("---sayhi?4",self.name)return?'test'm?=?MyClass()
m.sayhi2()
m.sayhi2_2(m)????#調用時將參數給參進去
print(m.sayhi4)
#?m.sayhi3()
#?MyClass.sayhi3()

類的屬性方法應用:

class?Attribute(object):def?__init__(self,name):self.name=?nameself.__food=?None@property?????#將類的方法變成類的靜態屬性def?eat(self):print("%s?eating?%s......"?%(self.name,self.__food))@eat.setter???#修改屬性def?eat(self,food):print("set?to?food:",food)self.__food=?food@eat.deleterdef?eat(self):??#刪除屬性del?self.__food
d?=?Attribute("dayi")
#?print(d.__dict__)
d.eat
d.eat?=?"noodle"
d.eat??????#修改屬性后調用屬性
del?d.eat????#刪除屬性
d.eat????????#刪除時調用屬性會報錯

6、類的成員方法

(1)__doc__

??作用:獲取類的描述信息

class?Dayi():"""welcome?to?...."""def?func(self):"""func"""pass
print(Dayi.__doc__)???#會打印class的描述信息

(2)__module__

??作用:表示當前操作的對象在那個模塊

? ?__class__

??作用:表示當前操作的對象的類是什么

from?lib?import?Dayi
tim?=?Dayiprint(tim.__module__)
print(tim.__class__)

(3)__call__

??作用:構造方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對于__call__ 方法的執行是由對象后加括號觸發的,即:對象() 或者 類()()

class?Call():def?__init__(self):passdef?__call__(self,?*args,?**kwargs):print("__call__")obj?=?Call()????#執行__init__
obj()???????????#執行__call__

(4)__dict__

??作用:查看類或對象中的所有成員,以字典的形式顯示,

(5)__str__

??作用:如果一個類中定義了__str__方法,那么在打印 對象 時,默認輸出該方法的返回值

class?Dayi(object):def?dayi123(self):print("dayi123")def?__str__(self):return?"hello"obj?=?Dayi()
print(obj)???#沒有__str__時輸出類的內存地址,有__str__時,輸出值

(6)__getitem__、__setitem__、__delitem__

??作用:用于索引操作,如字典。以上分別表示獲取、設置、刪除數據

class?Foo(object):def?__init__(self):self.data?=?{}def?__getitem__(self,?key):print('__getitem__',?key)return?self.data.get(key)???#讀取字典中key的值def?__setitem__(self,?key,?value):print('__setitem__',?key,?value)self.data[key]?=?value???????#設置字典中keydef?__delitem__(self,?key):print('__delitem__',?key)del?self.data[key]?#刪除data中的為key的數據obj?=?Foo()
obj['name']?=?"hehe"
print(obj.__dict__)
print(obj.data)
#?del?obj["name"]????#刪除時自動觸發__delitem__
result?=?obj['k1']??#?自動觸發執行?__getitem__
print(obj.__dict__)
obj['k2']?=?'kk2'??#?自動觸發執行?__setitem__
print(obj.__dict__)??#查看類的字典時,類的字典內容為{'data':?{'k2':?'kk2',?'name':?'hehe'}}
del?obj['k2']
print(obj.__dict__)