python中面向對象編程
編程范式:
編程是 程序 員 用特定的語法+數據結構+算法組成的代碼來告訴計算機如何執行任務的過程 , 一個程序是程序員為了得到一個任務結果而編寫的一組指令的集合,正所謂條條大路通羅馬,
實現一個任務的方式有很多種不同的方式, 對這些不同的編程方式的特點進行歸納總結得出來的編程方式類別,即為編程范式。 不同的編程范式本質上代表對各種類型的任務采取的不同的解決問題的思路,
大多數語言只支持一種編程范式,當然也有些語言可以同時支持多種編程范式。 兩種最重要的編程范式分別是面向過程編程和面向對象編程。
1.函數式:
將某功能封裝到函數中,日后便無需重復編程,僅調用函數即可。
2.面向過程
procedure-oriented Programming :根據業務邏輯從上到下寫代碼,函數是Python內建支持的一種封裝,我們通過把大段代碼拆成函數,通過一層一層的函數調用,
就可以把復雜任務分解成簡單的任務,這種分解可以稱之為面向過程的程序設計。函數就是面向過程的程序設計的基本單元
3.面向對象:
對函數進行分類和封裝,讓開發“更快更好更強",Object Oriented Programming,簡稱OOP,是一種程序設計思想。OOP把對象作為程序的基本單元,
一個對象包含了數據和操作數據的函數。
python中面向對象的基本概念
1.類(Class): 用來描述具有相同的屬性和方法的對象的集合。它定義了該集合中每個對象所共有的屬性和方法。對象是類的實例。
2.類變量:類變量在整個實例化的對象中是公用的。類變量定義在類中且在函數體之外。類變量通常不作為實例變量使用。
3.數據成員:類變量或者實例變量用於處理類及其實例對象的相關的數據。
4.方法重寫:如果從父類繼承的方法不能滿足子類的需求,可以對其進行改寫,這個過程叫方法的覆蓋(override),也稱為方法的重寫。
5.實例變量:定義在方法中的變量,只作用於當前實例的類。
6.繼承:即一個派生類(derived class)繼承基類(base class)的字段和方法。繼承也允許把一個派生類的對象作為一個基類對象對待。
例如,有這樣一個設計:一個Dog類型的對象派生自Animal類,這是模擬"是一個(is-a)"關系(例圖,Dog是一個Animal)。實例化:創建一個類的實例,類的具體對象。
7.方法:類中定義的函數。
8.對象:通過類定義的數據結構實例。對象包括兩個數據成員(類變量和實例變量)和方法
創建一個類:
'''類的屬性'''
class_suite # 類體
類的幫助信息可以通過ClassName.__doc__開查看
class_suite 由類成員,方法,數據屬性組成。
構造函數:對實例化的對象進行初始化操作
實例:
定義一個員工類:
#!/usr/bin/env python # -*- coding: UTF-8 -*- class Employee(object): '所有員工的基類' empCount = 0 ) def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary
empCount變量是一個類變量,它的值將在這個類的所有實例之間共享。你可以在內部類或外部類使用Employee.empCount訪問
第一種方法__init__()方法是一種特殊的方法,被稱為類的構造函數或初始化方法,當創建了這個類的實例時就會調用該方法
理解此處的self是什么意思? self 接收的是創建的對象 ,
析構函數:
其中的“__del__”就是一個析構函數了,當使用del 刪除對象時,會調用他本身的析構函數,另外當對象在某個作用域中調用完畢,
在跳出其作用域的同時析構函數也會被調用一次,這樣可以用來釋放內存空間。
例子:
class People: def __init__(self,name,self.name = name self.age = self.sex = sex def eat(self): print("%s 開始吃飯了!" %self.name) def __del__(self): # 析構函數,程序即將提出時要執行的 print("程序就要開始退出了,請保存!") p1 = People("alex",12,"man") p1.eat()
執行結果為:
/usr/bin/python3.4 /home/sm/python/day06/testOriented_Object.py alex 開始吃飯了! 程序就要開始退出了,請保存!
創建對象:
要創建一個類的實例,你可以使用類的名稱,並通過__init__方法接受參數。
"創建 Employee 類的第一個對象"
emp1 = Employee("Zara", 2000)
"創建 Employee 類的第二個對象"
emp2 = Employee("Manni", 5000)
訪問屬性:
您可以使用點(.)來訪問對象的屬性。使用如下類的名稱.訪問類變量:
emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount
你可以添加,刪除,修改類的屬性:
emp1.age = 7 # 添加一個 'age' 屬性
emp1.age = 8 # 修改 'age' 屬性
del emp1.age # 刪除 'age' 屬性
你也可以使用以下函數的方式來訪問屬性:
getattr(obj, name[, default]) : 訪問對象的屬性。
hasattr(obj,name) : 檢查是否存在一個屬性。
setattr(obj,name,value) : 設置一個屬性。如果屬性不存在,會創建一個新屬性。
delattr(obj, name) : 刪除屬性。
類變量和成員變量的區別
類方法和成員方法的,靜態方法的區別?
類方法:是類對象所擁有的方法,需要用修飾器"@classmethod"來標識其為類方法,對於類方法,第一個參數必須是類對象,
一般 以"cls"作為第一個參數(當然可以用其他名稱的變量作為其第一個參數,但是大部分人都習慣以'cls'作為第一個參數的名字,
就最好用'cls' 了),能夠通過實例對象和類對象去訪問。
靜態方法:需要通過修飾器"@staticmethod"來進行修飾,靜態方法不需要多定義參數。
實例方法:在類中最常定義的成員方法,它至少有一個參數並且必須以實例對象作為其第一個參數,一般以名為'self'的變量作為第一個參數
(當然可以以其他名稱的變量作為第一個參數)。在類外實例方法只能通過實例對象去調用,不能通過其他方式去調用
例如:
class people(object): __country = "china" # 列、類變量 # 類方法通過 classmethod修飾 @classmethod # 類方法 def getCountry(cls): return cls.__country @classmethod def SetCountry(cls,country): cls.__country = country # 靜態方法通過 staticmethod修飾 @staticmethod def getCountry2(): return people.getCountry() #實例方法 def say(self): print("My country is %s" %people.getCountry2()) print(people.getCountry()) people.SetCountry("Japan") print(people.getCountry()) print(people.getCountry2()) p1 = people() p1.say()
運行結果為:
1 china 2 Japan 3 Japan 4 My country is Japan
對於類屬性和實例屬性,如果在類方法中引用某個屬性,該屬性必定是類屬性,而如果在實例方法中引用某個屬性(不作更改),
並且存在同名的類屬 性,此時若實例對象有該名稱的實例屬性,則實例屬性會屏蔽類屬性,即引用的是實例屬性,若實例對象沒有
該名稱的實例屬性,則引用的是類屬性;如果在實例方 法更改某個屬性,並且存在同名的類屬性,此時若實例對象有該名稱的實例屬性,
則修改的是實例屬性,若實例對象沒有該名稱的實例屬性,則會創建一個同名稱的 實例屬性。想要修改類屬性,如果在類外,
可以通過類對象修改,如果在類里面,只有在類方法中進行修改。
從類方法和實例方法以及靜態方法的定義形式就可以看出來,類方法的第一個參數是類對象cls,那么通過cls引用的必定是類對象的屬性和方法;
而實例方法的第一個參數是實例對象self,那么通過self引用的可能是類屬性、也有可能是實例屬性(這個需要具體分析),不過在存在相同名稱的類屬性 和實例屬性的情況下,
實例屬性優先級更高。靜態方法中不需要額外定義參數,因此在靜態方法中引用類屬性的話,必須通過類對象來引用。
python中的繼承:
1)在Python中,如果父類和子類都重新定義了構造方法__init( )__,在進行子類實例化的時候,子類的構造方法不會自動調用父類的構造方法,必須在子類中顯示調用。
2)如果需要在子類中調用父類的方法,需要以 父類名.方法 這種方式調用,以這種方式調用的時候,注意要傳遞self參數過去。
對於繼承關系,子類繼承了父類所有的公有屬性和方法,可以在子類中通過父類名來調用,而對於私有的屬性和方法,子類是不進行繼承的,因此在子類中是無法通過父類名來訪問的。
此時有一個問題就是如果SubClass沒有重新定義構造方法,它會自動調用哪個父類的構造方法?這里記住一點:以第一個父類為中心。如果 SubClass重新定義了構造方法,
需要顯示去調用父類的構造方法,此時調用哪個父類的構造方法由你自己決定;若SubClass沒有重新定義構造方 法,則只會執行第一個父類的構造方法。並且若SuperClass1和SuperClass2中有同名的方法,
通過子類的實例化對象去調用該方法時調用的 是第一個父類中的方法。
例如:
class test1(object): def test(self): print("in the test1!") class university(object): student_list = [] tearcher_list = [] def __init__(self,name): self.name = name def show_teacher(self): for index,teacher in enumerate(university.tearcher_list): print(index,teacher) def show_student(self): for index,student in enumerate(university.student_list): print(index,student) # 父類 class universityMember(object): def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def getName(self): return self.name def getAge(self): return self.age def getSex(self): return self.sex def test(self): print("in the universityNumber") # 子類 學生 class student(test1,universityMember): def __init__(self,name,age,sex,stu_id): super(student,self).__init__(name,age,sex) self.stu_id = stu_id def getStu_id(self): return self.stu_id def showInfo(self): print(""" =========Student %s information is================== name:%s age:%s sex:%s stu_id:%s """%(self.name,self.name,self.age,self.sex,self.stu_id)) # 子類老師 class teacher(universityMember): def __init__(self,name,age,sex,salary): super(teacher,self).__init__(name,age,sex) self.salary = salary def teach(self,course): print("%s teach course!" %self.name) def getSalary(self): return self.salary def showInfo(self): print(""" =========Student %s information is================== name:%s age:%s sex:%s salary:%s """%(self.name,self.name,self.age,self.sex,self.salary)) s1 = student("alex",23,"男",1002) s1.test() s1.showInfo()
運行結果為:
1 Testing started at 下午11:14 ... 2 in the test1! 3 4 =========Student alex information is================== 5 name:alex 6 age:23 7 sex:男 8 stu_id:1002
python2經典類是按照深度優先繼承的。
python2新式類是按照廣度優先繼承的。
python3中經典類、新式類是按照廣度優先搜索進行的。
python中的多態:
多態性(polymorphisn)是允許你將父對象設置成為和一個或更多的他的子對象相等的技術,賦值之后,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。
簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。
那么,多態的作用是什么呢?我們知道,封裝可以隱藏實現細節,使得代碼模塊化;繼承可以擴展已存在的代碼模塊(類);它們的目的都是為了——代 碼重用。
而多態則是為了實現另一個目的——接口重用!多態的作用,就是為了類在繼承和派生的時候,保證使用“家譜”中任一類的實例的某一屬性時的正確調用。Pyhon不直接支持多態,但可以間接實現
1 #!/usr/bin/env python 2 # _*_ encoding:utf-8 _*_ 3 # author:snate 4 5 class Animal: 6 def __init__(self, name): # Constructor of the class 7 self.name = name 8 9 def talk(self): # Abstract method, defined by convention only 10 raise NotImplementedError("Subclass must implement abstract method") 11 12 13 class Cat(Animal): 14 def talk(self): 15 return 'Meow!' 16 17 18 class Dog(Animal): 19 def talk(self): 20 return 'Woof! Woof!' 21 22 23 animals = [Cat('Missy'), 24 Dog('Lassie')] 25 26 for animal in animals: 27 print(animal.name + ': ' + animal.talk())