終因而來到了Python的面向對象編程,之前是沒有接觸過其它的面向對象編程的語言,所以學習這一部分是至關帶勁的,這裏也總結一下。
python
1.面向對象編程的相關名詞及解釋編程
世界萬物,皆可分類,一切皆爲對象。ssh
所謂的面向對象編程,指的是一種編程的思想,經過對具體代碼實現過程(面向過程編程)的不斷抽象,以造成一個個的類別,以提升咱們進行大型程序編寫的效率(面向對象的具體實現須要面向過程,大型程序也能夠用面向過程來編寫,只是比較麻煩)。對於面向對象編程的相關名詞和解釋以下:ide
對象 :類的實體\一個叫Rain的好色的男人函數
類:人\動物\機器學習
方法:人會走,會思考\狗會叫,會咬人\定義一個類的各個功能測試
消息傳遞:狗叫了,人聽見了,就叫通訊ui
繼承:狗都四條腿走路this
封裝:人不能引用狗的特性,好比四條腿走路spa
多態性:一個叫的功能,多是低吼,也但是大聲叫
抽象性:簡化複雜的現實問題的途徑,它能夠爲具體問題找到最恰當的類定義
對「類」這個名詞舉個簡單的例子:
杯子:類
這個杯子:對象(實體),屬於「杯子」這個類
對「方法」這個名詞舉個例子:動態方法(動態屬性)與靜態方法(靜態方法能夠理解爲類的屬性)。
2.類、對象、方法
關於三者的關係,用下面的一張圖片能夠很是清晰明確的說明:
3.類的語法:第一個面向對象程序
程序代碼以下: class dog: #定義一個類 def name(self): #定義類的方法 print "Hello master, my name is Python." D = dog() #類的實例化,產生類的對象,若是不實例化,將沒法訪問該類 D.name() #使用類的方法 執行狀況以下: xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python myclass4.py Hello master, my name is Python.
4.類的方法:有關self
類的方法(類函數)與普通的函數只有一個特別的區別——它們必須有一個額外的第一個參數名稱,可是在調用這個方法的時候你不爲這個參數賦值,Python會提供這個值。這個特別的變量指對象自己,按照慣例它的名稱是self。
如你有一個類稱爲MyClass和這個類的一個實例MyObject。當你調用這個對象的方法MyObject.method(arg1, arg2)的時候,這會由Python自動轉爲MyClass.method(MyObject, arg1, arg2)。
類中若是有多個不一樣的方法,而且類中的變量須要相互訪問,這時候就須要使用self即用類自身來做爲中間變量以進行變量在不一樣類中的傳遞了,能夠看下面的一個例子:
程序代碼以下: class Dog: class_object = 'food' #這是一個類變量 def sayHi(self): print 'Hi master , I am your little dog, who do you want me to bite...' favorate_food = 'bone' self.FavorFood = favorate_food #將favorate_food變爲全局變量,讓其它方法能夠引用 def eat(self, food_type): if food_type == self.FavorFood: #不一樣類方法之間的變量調用,須要經過類自己 print 'I like it very much..thanks' else: print 'Do not give me this bull shit...' d = Dog() d.sayHi() '''若是不調用sayHi(),則沒法將favorrate_food變成一個類變量,所謂類變量, 便是類下定義的第一級變量''' d.eat('bone') 執行狀況以下: xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python class7.py Hi master , I am your little dog, who do you want me to bite... I like it very much..thanks
固然這裏其實是把sayHi方法中的favorate_food變量變爲變中的全局變量,須要注意的是,下面的方法是不能夠的:
程序代碼以下: class Dog: class_object = 'food' def sayHi(self): print 'Hi master , I am your little dog, who do you want me to bite...' favorate_food = 'bone' def eat(self, food_type): if food_type == self.sayHi().favorate_food: #這樣使用是不行的 print 'I like it very much..thanks' else: print 'Do not give me this bull shit...' d = Dog() d.sayHi() d.eat('bone') 執行狀況以下: xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python class7.py Hi master , I am your little dog, who do you want me to bite... Hi master , I am your little dog, who do you want me to bite... Traceback (most recent call last): File "class7.py", line 16, in <module> d.eat('bone') File "class7.py", line 9, in eat if food_type == self.sayHi().favorate_food: AttributeError: 'NoneType' object has no attribute 'favorate_food'
上面程序不行是由於,self.sayHi()時,其實會執行sayHi()方法,由於它原本就是一個函數,而且沒有定義返回值,所以會返回None值,致使程序執行出錯。
上面的例子意在說明,不一樣類方法之間調用變量時,須要將其變爲全局變量,而且要經過self即類自己進行引用。即類下的各個方法(函數,name也認爲是一個函數),不能獨自相互通訊,必需要經過類做爲中間人來進行通訊,self即表明self自己,經過self.name便可完成通訊,因此在定義類下的方法時,必需要加一個參數,即self,來表明類自己,不然這個方法就不能被使用固然參數不必定要是self。
5.類的構造函數__init__()與解構函數__del__()
關於兩個函數的說明,能夠看下面一個例子:
程序代碼以下: class Person: def __init__(self,name,age): #構造函數,只要把類實例化,就會執行此函數 print 'I am being called right now...' self.Name = name self.Age = age def sayHi(self): #類的普通方法 print 'Hi my name is %s, i am %s years old' % (self.Name,self.Age) def __del__(self): #解構函數,當實例在內存中釋放時,纔會執行此函數 print 'I got killed just now...bye...', self.Name p = Person('Alex',29) p.sayHi() #del p print '*'*60 p2 = Person('Jack',40) p2.sayHi() #del p2 執行狀況以下: xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python person_class5.py I am being called right now... Hi my name is Alex, i am 29 years old ************************************************************ I am being called right now... Hi my name is Jack, i am 40 years old I got killed just now...bye... Jack I got killed just now...bye... Alex
能夠看到程序最後有兩行相同內容的輸出(除了名字不同),是由於程序結束時,會把該程序在內存中佔用的空間釋放,因而執行兩次解構函數(由於進行了兩次類的實例化),纔出現這樣的狀況爲了驗證這個結論,將程序代碼修改成以下並執行:
程序代碼以下: class Person: def __init__(self,name,age): print 'I am being called right now...' self.Name = name self.Age = age def sayHi(self): print 'Hi my name is %s, i am %s years old' % (self.Name,self.Age) def __del__(self): print 'I got killed just now...bye...', self.Name p = Person('Alex',29) p.sayHi() del p #其它不變,只是在作類的另外一個實例前,刪除該實例 print '*'*60 p2 = Person('Jack',40) p2.sayHi() #del p2 執行狀況以下: xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python person_class5.py I am being called right now... Hi my name is Alex, i am 29 years old I got killed just now...bye... Alex ************************************************************ I am being called right now... Hi my name is Jack, i am 40 years old I got killed just now...bye... Jack
上面的程序代碼及執行結果即可以說明,解構函數在類完成調用而且在內存中釋放時纔會執行。
6.類的公有屬性與私有屬性及其調用
類的公有屬性便是類下的普通方法,這些方法是能夠直接被調用的;而類的私有屬性只有在類中不一樣方法之間能夠相互調用,通常狀況下是不能在類外直接調用的。
能夠看下面一個例子:
程序代碼以下: class Person: def __init__(self,name,age): print 'I am being called right now...' self.Name = name self.Age = age def sayHi(self): print 'Hi my name is %s, i am %s years old' % (self.Name,self.Age) self.__talk() #能夠引用類中的私有屬性 def __talk(self): #私有屬性的定義方法 print "I'm private..." p=Person('Alex',29) p.sayHi() 執行狀況以下: xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python private6.py I am being called right now... Hi my name is Alex, i am 29 years old I'm private...
若是將代碼修改成以下,即在類外調用私有屬性:
程序代碼以下: class Person: def __init__(self,name,age): print 'I am being called right now...' self.Name = name self.Age = age def sayHi(self): print 'Hi my name is %s, i am %s years old' % (self.Name,self.Age) self.__talk() def __talk(self): print "I'm private..." p=Person('Alex',29) p.sayHi() p.__talk() #在類外經過普通方式調用類的私有屬性 執行狀況以下: xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python private6.py I am being called right now... Hi my name is Alex, i am 29 years old I'm private... Traceback (most recent call last): File "private6.py", line 17, in <module> p.__talk() AttributeError: Person instance has no attribute '__talk' #會出現找不到類方法的錯誤提示
固然能夠經過特殊的方法引用類中的私有屬性:
程序代碼: class Person: def __init__(self,name,age): print 'I am being called right now...' self.Name = name self.Age = age def sayHi(self): print 'Hi my name is %s, i am %s years old' % (self.Name,self.Age) self.__talk() def __talk(self): print "I'm private..." p=Person('Alex',29) p.sayHi() print '*'*30 p._Person__talk() 執行狀況以下: xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python private6.py I am being called right now... Hi my name is Alex, i am 29 years old I'm private... ****************************** I'm private...
7.類的繼承
類有分父類和子類,在有多個子類的狀況下,子類經過繼承父類的屬性或方法,就能夠節省不少代碼空間。能夠先看下面一個沒有參數傳遞的類的繼承簡單例子:
程序代碼以下: class person: #父類 def tell(self, name): print 'hi my name is', name class student(person): #子類,繼承父類 def study(sefl): print 'I am studying Py right now.' s = student() s.study() s.tell('MengFanHao') #子類繼承父類後即可以直接調用父類的方法 #在有多個須要同時執行相同功能的子類狀況下,使用類的繼承能夠節省代碼空間 執行狀況以下: xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python cla_with_no_arg9.py I am studying Py right now. hi my name is MengFanHao
看過上面的例子後,再看下面一個含有參數傳遞的例子,經過該例子也能夠很好地理解前面第2點中關於類、對象、方法的理解:
class SchoolMember: #父類,學校成員 school_name = 'Oldboy Linux edu.' #第一級變量,即類屬性 def __init__(self,name,gender,nationality = 'CN'): #構造函數 self.name = name self.gender = gender self.nation = nationality def tell(self): #普通的類方法 print 'Hi, my name is %s , I am from %s' % (self.name,self.nation) class Student(SchoolMember): #子類,學生,繼承父類學校成員的相關屬性 def __init__(self, Name, Gender, Class, Score, Nation = 'US'): #子類下的方法 SchoolMember.__init__(self, Name, Gender, Nation) #讓父類使用子類傳遞過去的參數 self.Class = Class self.Score = Score def payTuition(self, amount): #子類下的方法 if amount < 6499: print 'Get the fuck off...' else: print 'Welcome onboard!' class Teacher(SchoolMember): #子類,老師,繼承父類學校成員的相關屬性 def __init__(self, Name, Gender, Course, Salary, Nation = 'FR'): SchoolMember.__init__(self, Name, Gender, Nation) self.course = Course self.Salary = Salary def teaching(self): print 'I am teaching %s, i am making %s per month !' % (self.course, self.Salary) S1 = Student('WangFanHao', 'Male', 'Python', 'C+', 'JP') #實例化一個子類對象,學生 S1.tell() #直接繼承父類中的tell()方法 S1.payTuition(4999) #使用子類Student()自身中的類方法 print S1.school_name #直接繼承父類的一個屬性 print '*'*60 S2 = Student('ShitTshirt', 'Male', 'Linux', 'B') S2.tell() S2.payTuition(6500) #S2.age = 29 #print S2.age print '*'*60 T1 = Teacher('Alex', 'Male', 'C++', 5000) #實例化一個子類對象,學生 T1.tell() #直接繼承父類中的tell()方法 T1.teaching() #直接繼承父類的一個屬性 print 'S1.name:', S1.name #測試用,觀察輸出結果 print 'S2.name:', S2.name print 'T1.name:', T1.name 執行狀況以下: xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python class_continue8.py Hi, my name is WangFanHao , I am from JP Get the fuck off... Oldboy Linux edu. ************************************************************ Hi, my name is ShitTshirt , I am from US Welcome onboard! ************************************************************ Hi, my name is Alex , I am from FR I am teaching C++, i am making 5000 per month ! S1.name: WangFanHao S2.name: ShitTshirt T1.name: Alex
經過上面的例子即可以很好地理解類的繼承的做用了,即若是須要在多個子類中執行相同的代碼功能時,就能夠經過類的繼承來節省代碼空間。
8.類的屬性修改:setattr(),delattr()與getattr()
以上面程序爲例,作以下的演示:
首先在交互器中導入該類:
>>> import class_continue8 Hi, my name is WangFanHao , I am from JP Get the fuck off... Oldboy Linux edu. ************************************************************ Hi, my name is ShitTshirt , I am from US Welcome onboard! ************************************************************ Hi, my name is Alex , I am from FR I am teaching C++, i am making 5000 per month ! S1.name: WangFanHao S2.name: ShitTshirt T1.name: Alex >>> import tab >>> class_continue8. class_continue8.S1 class_continue8.__hash__( class_continue8.S2 class_continue8.__init__( class_continue8.SchoolMember class_continue8.__name__ class_continue8.Student class_continue8.__new__( class_continue8.T1 class_continue8.__package__ class_continue8.Teacher class_continue8.__reduce__( class_continue8.__class__( class_continue8.__reduce_ex__( class_continue8.__delattr__( class_continue8.__repr__( class_continue8.__dict__ class_continue8.__setattr__( class_continue8.__doc__ class_continue8.__sizeof__( class_continue8.__file__ class_continue8.__str__( class_continue8.__format__( class_continue8.__subclasshook__( class_continue8.__getattribute__(
setattrr():在類中添加屬性
1.子類有的屬性,屬於該子類的對象沒有定義,會繼承該屬性;若是有定義,則不會繼承子類的該屬性 >>> class_continue8.Student.age #原來Student類中並無age屬性 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: class Student has no attribute 'age' >>> setattr(class_continue8.S) class_continue8.S1 class_continue8.SchoolMember class_continue8.S2 class_continue8.Student >>> setattr(class_continue8.Student,'age',29) #在Student類中添加age屬性 >>> class_continue8.Student.age #再次查看age屬性 29 >>> class_continue8.S1.age #S1與S2做爲Student類的實例化對象,也會有age屬性 29 >>> class_continue8.S2.age 29 >>> setattr(class_continue8.S1,'age',26) >>> class_continue8.S1.age #此時S1對象有定義,所以不會繼承所屬子類的該屬性 26 2.子類的對象有的屬性,但在其所屬子類沒有定義,則該子類不會反繼承該屬性 >>> setattr(class_continue8.S1,'tuition',5000) #若是僅僅是在對象中添加tuition屬性 >>> class_continue8.Student.age 29 >>> class_continue8.Student.tuition #則在S1對象所屬的類Student中並不會有tuition屬性 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: class Student has no attribute 'tuition' >>> class_continue8.S1.tuition 5000 >>> class_continue8.S2.tuition #所以S2對象也不會有該屬性 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: Student instance has no attribute 'tuition' 3.父類有的屬性,子類中沒有定義,則子類會繼承該屬性;若是子類中有定義,則不會繼承 >>> setattr(class_continue8.SchoolMember,'name','Python') #在子類在沒有定義 >>> class_continue8.SchoolMember.name 'Python' >>> class_continue8.Student.name #所以子類會繼承該屬性 'Python' >>> setattr(class_continue8.SchoolMember,'age',25) #在父類中定義子類有定義的屬性 >>> class_continue8.SchoolMember.age 25 >>> class_continue8.Student.age #子類已經定義了age屬性,所以不會再繼承父類的該屬性 29
從上面的例子能夠看出,對於父類、子類、對象,屬性的優先級以本地定義的爲主,若是本地沒有定義,則繼承上一級的屬性,若是有定義,則使用本地的。
delattr():刪除類中的屬性
>>> class_continue8.SchoolMember.name 'Python' >>> delattr(class_continue8.SchoolMember,'name') >>> class_continue8.SchoolMember.name Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: class SchoolMember has no attribute 'name'
getattr()的主要用法以下:
程序代碼以下: class person: def tell(self, name): print 'hi my name is', name def study(sefl): print 'I am studying Py right now.' class student(person): def study(sefl): print 'I am studying Py right now.' p = person() vars = ['tell', 'study'] v1 = vars[0] getattr(p, v1)('Oldboy') 執行狀況以下: xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python cla_getattr_with_no_arg10.py hi my name is Oldboy
對於該程序,若是直接使用p.v1('name')來訪問類中的方法是不行的,會有以下的提示錯誤:
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python cla_getattr_with_no_arg10.py Traceback (most recent call last): File "cla_getattr_with_no_arg10.py", line 21, in <module> p.v1('Oldboy') AttributeError: person instance has no attribute 'v1'
所以getattr()的主要用途就在於有一個類有多個方法時,須要對該類的全部方法都執行一遍,那麼能夠將類中的方法都寫入一個列表中,再經過getattr()和循環的方法來完成,這樣就能夠節省不少代碼空間。