面向對象編程
object(對象)
什麼是對象
對象是指現實中的物體或實物
什麼是面向對象
把一切當作對象(實例),讓對象和對象之間創建關聯關係
對象都有什麼特徵
對象有不少屬性(名詞),用變量記錄屬性
姓名,年齡,性別等
對象有不少行爲(動做,動詞),用函數(方法)表示行爲
學習,吃飯,睡覺,踢球,工做
什麼是類class:
擁有相同屬性和行爲的對象分爲一組,即爲一個類
類是用來描述對象的工具,用類能夠建立同類對象
類的建立語句:
語法:class 類名(繼承列表):
'''類的文檔字符串'''
實例方法定義(類內的函數稱爲方法method)
類變量定義
類方法定義
靜態方法定義
做用:
一、建立一個類
二、用於描述此類對象的行爲和屬性
三、類用於建立此類的一個或多個對象(實例)python
class Dog:#定義一個類,類名爲Dog pass dog1 = Dog()#建立Dog類的一個對象 print(id(dog1))#140399880349568 dog2 = Dog()#建立Dog類的另外一個對象 print(id(dog2))#140399880349848 #相似於以下語句: int1 = int() int2 = int ()
類 和 對象
類 | 對象 實例
class | object instance
構造函數
表達式:類名([建立傳參列表])
做用:建立這個類的實例對象,並返回此實例對象的引用關係
實例(對象)說明
實例有本身的做用域和名字空間,能夠爲該實例添加實例變量(屬性)
實例能夠調用類方法和實例方法
實例能夠訪問類變量和實例變量
實例方法:
語法:calss 類名(繼承列表):
def 實例方法名(self,參數1,參數2...):
'''實例方法的的文檔字符串'''
語句塊
做用:用於描述一個對象的行爲,讓此類型的所有對象都擁有相同的行爲
說明:
一、實例方法實質是函數,是定義在類內的函數
二、實例方法至少有一個形參,第一個形參表明調用這個方法的實例,通常命名爲」self「
實例方法的調用語法:
一、實例.實例方法名(調用傳參)
二、類名.實例方法名(實例,調用傳參)編程
#此實例示意如何用實例方法(method)來描述Dog類的行爲 class Dog(): def eat(self,food): '''此方法用來描述小狗吃東西的行爲''' print("小狗正常吃:",food) def sleep(self,hour): print("小狗睡了",hour,'小時') dog1 = Dog()#建立一個Dog的類的實例 dog1.eat("狗糧") dog1.sleep(1) Dog.eat(dog1,"狗糧")#第二種方法調用實例方法 #對象不能調用類內沒有的方法
屬性 attribute(也叫實例變量)
每一個實例均可以有本身的變量,此變量稱爲實例變量(也叫屬性)
屬性的使用語法:實例名.屬性名
賦值規則:
一、首次爲屬性賦值,則建立此屬性
二、再次爲屬性賦值,則必改變屬性的綁定關係
做用:用來記錄對象自身的數據less
class Dog: pass #建立第一個對象 dog1 = Dog() dog1.kinds = '京巴' #添加屬性kinds dog1.color = '白色' #添加屬性color dog1.color = '京巴' #改變屬性的綁定關係
實例方法和實例變量(屬性)結合使用編程語言
class Dog: def eat(self,food): print("%s的%s正在吃%s"%(self.color,self.kinds,food)) dog1 = Dog() dog1.kinds = '京巴' #添加屬性kinds dog1.color = '白色' #添加屬性color dog1.eat("狗糧")#該語句不能放在kinds和color屬性被添加以前 dog2 = Dog() dog2.kinds = '哈士奇' #添加屬性kinds dog2.color = '黑色' #添加屬性color dog2.eat("包子")
刪除屬性
用del語句能夠刪除一個對象的實例變量
語法:
del 對象.實例變量名
示例:
class Cat:
pass
c1 = Cat() #建立實例對象
c1.color = "白色"#添加屬性
del c1.color #刪除屬性
print(c1.color)#屬性錯誤
初始化方法:
做用:對新建立的對象添加實例變量(屬性)或相應的資源
語法:
class 類名(繼承列表):
def __init__(self[,形參列表]):
語句塊
說明:
一、初始化方法名必須爲__init__不可改變
二、初始化方法會在構造函數建立實例後自動調用,且將實例自身經過第一個參數self傳入__init__方法
三、構造函數的實參將經過__init__方法的形參傳入__init__方法中
四、初始化方法內部若是須要返回,則只能返回Noneide
class Car(): def __init__(self,c,b,m):#此方法只能怪返回None print("__init__方法被調用") self.color = c self.brand = b self.model = m #return 1 #TypeError: __init__() should return None, not 'int' car = Car("紅色","奧迪","A4")#Car()構造函數首先建立一個空的(沒有屬性的對象),而後把這個對象傳遞給__init__方法
析構方法:
語法:class 類名(繼承列表):
def __del__(self):
語句塊
說明:析構方法在對象銷燬時被自動調用
做用:清理此對象所佔用的資源
python不建議在析構方法中作任何事情,由於對象銷燬的時間難以肯定
預置實例屬性:
__dict__屬性:
此屬性綁定一個存儲此實例自身實例變量(屬性)的字典,也能夠存儲類中的變量,文檔字符串,方法
示例:
class Dog():
pass
dog = Dog()
print(dog.__dict__)#{}
dog.kinds = "aa"
print(dog.__dict__)#{"kinds":"aa"}
dog.__dict__["color"]= "red"
__class__屬性:
此屬性用來綁定建立此實例的類
做用:能夠藉助此屬性來訪問建立此實例的類
示例:
class Dog()
pass
dog1=Dog()
dog2 = dog1.__class__()#等同於dog2 = Dog()
面向對象的綜合示例
有兩我的:
一、姓名:張三 年齡:35
二、姓名:李四 年齡:38
行爲:
一、交別人學東西teach
二、賺錢
三、借錢
事情:
張三 教 李四 學 python
李四 教 張三 學 跳皮筋
張三 上班賺了 1000 元錢
李四 向 張三 借了 200 元錢函數
class Person(): '''人類,用於描述人的行爲和屬性''' def __init__(self,name,age): self.name = name self.age = age self.money = 0 def teach(self,other,things): print(self.name,"教",other.name,"學",things) def make_money(self,money): self.money+=money print(self.name,"上班賺了",money,"元錢") def borrow_money(self,other,money): if other.money > money:# print(self.name,"向",other.name,"借了",money,"元錢") other.money -= money self.money += money print(other.name,"沒有錢借給",self.name) def show_info(self): print(self.age,"歲的",self.name,"存有",self.money,"元錢") p1 = Person("張三",35) p2 = Person("李四",38) p1.teach(p2,"python") p2.teach(p1,"跳皮筋") p1.make_money(1000) p2.borrow_money(p1,200) p1.show_info() p2.show_info() # 張三 教 李四 學 python # 李四 教 張三 學 跳皮筋 # 張三 上班賺了 1000 元錢 # 李四 向 張三 借了 200 元錢 # 張三 沒有錢借給 李四 # 35 歲的 張三 存有 800 元錢 # 38 歲的 李四 存有 200 元錢
用於判斷類的函數:
isinstance(obj,class_or_tuple)返回一個對象obj是否爲某個類class或某些類的實例,若是是返回True,不然返回False
type(obj) 返回對象的類型
示例:
class Dog:
pass
class Cat:
pass
animal = Dog()
isinstance(animal,Dog) #True
isinstance(animal,Cat) #False
isinstance(animal,(Cat,int,list)) #False
isinstance(animal,(Cat,int,list,Dog)) #True工具
類變量 class variable(也叫類屬性):
類變量是類的屬性,此屬性屬於類
做用:用來記錄類的相關數據
說明:
一、類變量能夠經過類直接訪問
二、類變量能夠經過類的實例直接訪問
三、類變量能夠經過類的實例的__class__屬性訪問
實例:
class Human:
count = 0 #建立類變量學習
class Human: count =0 #建立一個類變量 print("Human的類變量count=",Human.count)#0 h1 = Human() print("用h1對象訪問Human的count變量",h1.count)#0 print("用h1對象的__class__屬性訪問Human的count變量",h1.__class__.count)#0 h1.count = 100 #此處hi建立實例變量,經過實例不能經過這樣的方式修改類變量,能夠經過__class__屬性來修改 print(h1.count) #100,會優先尋找實例變量,若是沒有實例變量纔會訪問到類變量 print(Human.count) #0 print(h1.__class__.count) #0
類變量的應用案例:
用類變量來記錄對象的個數測試
class Car: count = 0 def __init__(self,info):#建立類變量,用來記錄汽車對象的總數 print(info,"被建立") self.data = info#記錄傳入的數據 self.__class__.count +=1 #讓車的總數加1 def __del__(self): print(self.data,"被銷燬") self.__class__.count -=1#讓車的總數減1 print("當前汽車總數是",Car.count) car1 = Car("奧迪") print(Car.count) car2 = Car("奔馳") car3 = Car("大衆") print(Car.count)
類的文檔字符串:
類內的一個沒有賦值給任何變量的字符串是類的文檔字符串
說明:
一、類的文檔字符串用類的__doc__屬性能夠訪問
二、類的文檔字符串能夠用help()函數查看
類的__slots__列表:
做用:限定一個類的實例只能有固定的屬性(實例變量),一般爲了防止錯寫屬性名而發生運行時錯誤
說明:含有__slots__列表的類建立的實例對象沒有__dict__屬性,即此實例不用字典來保存對象的屬性(實例變量)spa
class Student: __slots__ = ["name","score","aa"]#此處表示該實例對象最多隻能有兩個實例變量 def __init__(self,name,score): self.name = name self.score = score s1 = Student("小張",58) print(s1.score) s1.socre = 100 #此處寫錯了屬性名,但在運行時不會報錯 ,若是添加了__slots__變量後就會產生AttributeError: 'Student' object has no attribute 'socre' print(s1.score)
類方法 @classmethod
類方法是描述類的行爲的方法,類方法屬於類
說明:
一、類方法須要用@classmethod裝飾器定義
二、類方法至少有一個形參,第一個形參用於綁定類,約定寫爲‘cls’
三、類和該類的實例均可以調用類方法
四、類方法不能訪問此類建立的實例的屬性(只能訪問類變量)
class Car: count =0 #類變量 @classmethod def getTotalCount(cls): '''此方法爲類方法,第一個參數cls,表明調用此方法的類''' return cls.count @classmethod def updateCount(cls,number): cls.count += number print(Car.getTotalCount())#用類來調用類方法 #Car.count += 1 #面向對象思想不提倡直接操做屬性 Car.updateCount(2) print(Car.getTotalCount()) c1 = Car() c1.updateCount(100)#類的實例能夠訪問類方法,是把c1.__class__傳給cls print(c1.getTotalCount())
問題:
一、類方法屬於類
二、實例方法屬於該類的實例
三、類內能不能有函數,既不屬於類又不屬於類的實例?
靜態方法 @staticmethos
靜態方法不屬於類,也不屬於類的實例,它至關於定義在類內的普通函數,只是它的做用域屬於類
class A: @staticmethod def myadd(x,y): '''此方法爲靜態方法,此方法的形參不須要傳入類或實例''' return x+y print("1+2=",A.myadd(1,2)) a = A() print("100+200=",a.myadd(100,200)) print(myadd(10,20))#NameError: name 'myadd' is not defined
繼承 inheritance 和 派生 derived
什麼是繼承/派生
一、繼承是指從已有的類中衍生出新類,新類具備原有類的行爲和屬性,並能擴展新的行爲和屬性
二、派生就是從一個已有類中衍生(建立)新類,在新類上能夠添加新的屬性和行爲
繼承和派生的目的:
一、繼承是延續舊類的功能
二、派生是爲了在舊類的基礎上添加新的功能
做用:
一、用繼承派生機制,能夠將一些共有功能加在基類中,實現代碼的共享
二、在不改變基類的基礎上改變原有的功能
繼承/派生的名詞:
基類(base class),超類(super class),父類(father class)
派生類(derived class),子類(child class)
單繼承:
語法:class 類名( 基類名):
語句塊
說明:單繼承是指派生類由一個基類衍生出來的類
繼承說明:
一、任何類都直接或間接的繼承自object類
二、object類是一切類的超類(祖類)
類的__base__屬性:
__base__屬性用來記錄此類的基類
說明:類名.__base__ 返回的是繼承的第一個類
覆蓋 override:
什麼是覆蓋:
覆蓋是指在有繼承關係的類中,子類中實現了與基類同名的方法,在子類實例調用該方法時,實例調用的是子類中的覆蓋版本的方法,這種現象叫作覆蓋
問題:當覆蓋發生時,子類對象可否訪問父類中的方法?
子類對象顯式調用基類方法的方式:
基類名.方法名(實例,實際調用傳參)
super 函數:
super(type,obj) 返回綁定超類的實例
super() 返回綁定超類的實例,等同於:super(__class__,實例方法的第一個參數,必須在方法內調用)
def work(self): print("A.walk()被調用") class B(A): def work(self): print("B.walk()被調用") def super_work(self): #此處能調用超類的work方法 #super(B,self).work() #A.walk() #super(__class__,self).work() #A.walk()被調用,在一個類內有一個__class__屬性, super().work() #A.walk(),在一個實例方法中__class__和self 都是已知的能夠省略 b = B() b.work() # B.walk()被調用 b.__class__.__base__.work(b) #A.walk()被調用,使用顯式的方法調用超類的方法 super(B,b).work()#A.walk()被調用,super(B,b)返回的是B類的超類的對象實例 b.super_work()
顯示調用基類的初始化方法:
當子類中實現了__init__方法時,基類的__init__方法並不會被調用,此時須要顯式調用
class Human(): def __init__(self,n,a): self.name = n self.age = a def infos(self): print("姓名:",self.name) print("年齡",self.age) class Student(Human): def __init__(self,n,a,s): super().__init__(n,a)#使用超類中的__init__方法給name,age賦值 self.score = s s1 = Student("小張",20,100) s1.infos()
用於類的函數:
issubclass(cls,class_or_tuple):
判斷一個類是否繼承自其它的類,若是此類cls是class或tuple中的一個派生子類則返回True,不然返回False
說明:cls是class的子類的子類...也返回True
查看python內建類的繼承關係的方法:
help(__bulitins__)
封裝 enclosure
一、封裝是指隱藏類的實現細節,讓使用者不用關心這些細節
二、封裝的目的是讓使用者儘量少的使用實例變量(屬性)進行操做
私有屬性:
python類中,以雙下劃線「__」開頭的,不以雙下劃線結尾的標識符爲私有成員,在類的外部沒法直接訪問
class A: def __init__(self): self.__p1 = 100#__p1爲私有屬性,在類的外部不能調用 def test(self): print(self.__p1)#在類內能夠調用私有屬性 self.__m1() #A類的方法能夠調用私有方法 def __m1(self): '''我是私有方法,只有我本身的類的方法才能調用我''' print("我是A類的__m1方法") a = A() #print(a.__p1)#在類外看不到__p1屬性,訪問失敗 a.test() #a.__m1() #出錯,沒法調用私有方法
多態 polymorphic
字面意思:「多種狀態」
多態是指在繼承/派生關係的類中,調用基類對象的方法,實際能調用子類的覆蓋版本方法的現象叫多態
說明:
多態調用的方法與對象相關,不與類型相關
Python的所有對象都只有「運行時狀態(動態)」,沒有「C++/Java」裏的「編譯時狀態(靜態)」
class Shape(): def draw(self): print("Shape.draw被調用") class Point(Shape): def draw(self): print("正在畫點") class Circle(Point): def draw(self): print("正在畫圓") def my_draw(s): s.draw() # 此處會調用誰的方法,此處顯示多態中的動態 s1 = Circle() s2 = Point() s3 = Shape() my_draw(s1)#正在畫圓 my_draw(s2)#正在畫點 my_draw(s3)#Shape.draw被調用
面向對象的編程語言的特徵:
繼承
封裝
多態
如:C++(支持多繼承)/ Java /Python(支持多繼承)/Swift /C#
多繼承 multiple inheritance
多繼承是指一個子類繼承自兩個或兩個以上的基類
語法:
class 類名(基類名1,基類名2....):
語句塊
說明:
一、一個子類同時繼承自多個父類,父類中的方法能夠同時被繼承下來
二、若是兩個父類中有同名的方法,而在子類中又沒有覆蓋此方法時,調用結果難以肯定
多繼承的問題(缺陷):
標識符(名字空間衝突的問題)
要謹慎使用多繼承
class Car: def run(self,speed): print("汽車以",speed,"千米/小時的速度行駛") class Plane: def fly(self,height): print("飛機以海拔",height,"的高度飛行") class PlaneCar(Car,Plane): pass p1 = PlaneCar() p1.fly(10000) p1.run(300)
多繼承的MRO(Method Resolution Order)問題:
類內的__mro__屬性用來記錄繼承方法的查找順序
class A: def m(self): print("A.m()被調用") class B: def m(self): print("B.m()被調用") class AB(A,B): pass ab = AB()#多繼承的調用方法,從左至右,,能夠根據AB.__mro__來查看繼承的順序 ab.m()
class A: def m(self): print("A.m()") class B(A): def m(self): print("B.m()") class C(A): def m(self): print("C.m()") class D(B,C): def m(self): print("D.m()") d = D() print(D.__mro__)#(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) d.m() ############################################################################################################################################ class A: def m(self): print("A.m()") class B(A): def m(self): print("B.m()") super().m()# 此處調用的是C類的方法,在多繼承中super()的窒執行順序是按照__mro__的順序來查找的 class C(A): def m(self): print("C.m()") class D(B,C): def m(self): print("D.m()") super().m()#此處調用B類的m方法 d = D() d.m() print(D.__mro__) # D.m() # B.m() # C.m() # (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
函數重寫 override:
重寫是在自定義的類內添加相應(內建函數的方法)的方法,讓自定義的類生成的對象(實例)像內建對象同樣進行內建的函數操做
class MyNumber: pass n1 = MyNumber() x = len(n1) print(x) #TypeError: object of type 'MyNumber' has no len() ################################################################################### class MyNumber: def __len__(self):#重寫了len方法,重寫的必須是內建函數的方法 return 10 n1 = MyNumber() x = len(n1) #至關於x = n1.__len__() print(x) #10
對象轉化爲字符串函數重寫
repr(obj)返回一個表明此對象的表達式字符串,一般:eval(repr(obj)) == obj
str(obj)經過給定的對象返回一個字符串(這個字符串一般是給人看的)
class MyNumber: def __init__(self,value): self.data = value n1 = MyNumber(100) print(str(n1))#<__main__.MyNumber object at 0x7f676201cfd0>,至關於調用n1.__str__(self) print(repr(n1))#<__main__.MyNumber object at 0x7f676201cfd0>,至關於調用n1.__repr__(self) ######################################################################################### class MyNumber: def __init__(self,value): self.data = value def __str__(self): return "數字:%d" % self.data def __repr__(self): return "MyNumber(%d)"% self.data n1 = MyNumber(100) print(str(n1))#數字:100,至關於調用n1.__str__(self) print(repr(n1))#MyNumber(100),至關於調用n1.__repr__(self) #n2 = eval(str(n1))#SyntaxError: invalid character in identifier n2 = eval(repr(n1))#能夠建立n2對象實例
對象轉字符串函數的重寫方法:
repr()函數的重寫方法:
def __repr__(self):
return 可以表達self內容的字符串(能夠經過eval()方法反推)
str()函數的重寫方法:
def __str__(self):
return 人能看懂的字符串
說明:
一、str(obj)函數優先調用obj.__str__()方法返回字符串
二、若是obj沒有__str__()方法,則調用obj.__repr__()方法返回的字符串
三、若是obj沒有__repr__()方法,則調用object類的__repr__()實例方法顯示<XXXXX>格式的字符串
四、print(對象)至關於print(str(對象)),一個對象(實例)就是首先尋找__str__方法,在尋找__repr__方法
數值轉換函數的重寫:
def __complex__(self) complex(obj)函數調用
def __int__(self) int(obj)函數調用
def __float__(self) float(obj)函數調用
def __bool__(self) bool(obj)函數調用
class MyNumber: def __init__(self,value): self.data = value def __repr__(self): print("__repr__被調用") return "MyNumber(%d)"% self.data def __int__(self): '''此方法int(obj)函數重載,必須返回整數,此方法一般用於制定自定義對象如何轉爲整數的規則''' return self.data n1 = MyNumber(100) print(type(n1))#<class '__main__.MyNumber'> n = int(n1) #至關於n1.__int__(self) print(type(n))#<class 'int'> print(n)
內建函數的重寫:
__abs__ abs(obj)
__len__ len(obj)
__reversed__ reversed(obj)
__round__ round(obj)
'''自定義一個MyList類,與系統內建的類同樣,用來保存有前後順序關係的數據''' class MyList(): def __init__(self,iterator=[]): self.data = [x for x in iterator] def __repr__(self): return "MyList(%r)" % self.data def __abs__(self): #return MyList([abs(x) for x in self.data]) #上一句語句能夠用以下生成器表達式代替以防止過多的佔用內存 return MyList((abs(x) for x in self.data)) def __len__(self): return len(self.data) myl = MyList([1,-2,3,-4]) print(myl)#MyList([1, -2, 3, -4]) print(abs(myl))#MyList([1, 2, 3, 4]) print("原來的列表:",myl)#原來的列表: MyList([1, -2, 3, -4]),原來的列表 myl2 = MyList(range(10)) print("myl2的長度是:",len(myl2))#10 print("myl的長度是:",len(myl)) #4
布爾測試函數的重寫:
格式:def __bool__(self):
....
做用:
一、用於bool(obj)函數取值
二、用於if語句真值表達式中
三、用於while語句真值表達式中
說明:
一、優先調用__bool__方法取值
二、若是不存在__bool__方法,則用__len__()方法取值,後判斷是否爲零值,若是不爲零返回True,不然返回False
三、若是再沒有__len__方法,則直接返回True
class MyList(): def __init__(self,iterator=[]): self.data = [x for x in iterator] def __repr__(self): return "MyList(%r)" % self.data def __abs__(self): #return MyList([abs(x) for x in self.data]) #上一句語句能夠用以下生成器表達式代替以防止過多的佔用內存 return MyList((abs(x) for x in self.data)) def __len__(self): print("__len__方法被調用") return len(self.data) myl = MyList([1,-2,3,-4]) myl2 = MyList([]) print(bool(myl))# True print(bool(myl2))# False if myl2:#在此處會查找__bool__,若是沒有再查找__len__,再沒有直接返回True pass while myl2:#在此處會查找__bool__,若是沒有再查找__len__,再沒有直接返回True pass
迭代器(高級):
什麼是迭代器
能夠經過next(it)函數取值的對象就是迭代器
迭代器協議:
迭代器協議是指對象可以使用next函數獲取下一項數據,在沒有下一項數據是觸發StopIterator來終止迭代的約定
實現方法:
類內須要有__next__(self)方法來實現迭代器協議
語法形式:
class MyIterator:
def __next__(self):
迭代器協議的實現
return 數據
什麼是可迭代對象:
一、是指能用iter(obj)函數返回迭代器的對象(實例)
二、可迭代對象內部必定要定義__iter__(self)方法來返回迭代器
可迭代對象的語法形式:
class MyIterable:
def __iter__(self):
語句塊
return 迭代器
class MyList: def __init__(self,iterator): '''自定義列表的初始方法,此方法建立一個data實例變量來綁定一個用來存儲數據的列表''' self.data = list(iterator) def __repr__(self): '''此方法爲了打印此列表的數據''' return 'MyList(%r)' % self.data def __iter__(self): '''有此方法就是可迭代對象,但要求必須返回迭代器''' print("__iter__方法被調用") return MyListIterator(self.data) class MyListIterator: '''此類用來建立一個迭代器對象,用此迭代器對象能夠迭代訪問MyList類型的數據''' def __init__(self,iter_data): self.cur = 0 #設置迭代器的初始值爲0表明列表下標 self.iter_data = iter_data def __next__(self): '''有此方法的對象才叫迭代器',此方法必定要實現迭代器協議''' print("__next__方法被調用") if self.cur >= len(self.iter_data): raise StopIteration #不然還沒有迭代完成,須要返回數據 r = self.iter_data[self.cur]# 拿到要送回去的數據 self.cur +=1 #將當前值向後移動一個單位 return r myl = MyList([2,3,5,7]) print(myl) for x in myl: print(x)
對象的屬性管理函數:
一、getattr(obj,name[,dafault]) 從一個對象獲得對象的屬性;gettattr(x,'y')等同於x.y;當屬性y不存在時,若是有default參數,則返回default,若是沒有給出default則產生一 個AttributeError錯誤
二、hasattr(obj,name) 用給定的name返回obj是否有屬性,若是有返回True,不然返回False,此種作法能夠避免在getattr(obj,name)時引起錯誤
三、setattr(obj,name,value) 給對象obj的名爲name的屬性設置相應的值value,setattr(x,'y',v)等同於x.y = v
四、delattr(obj,name) 刪除對象obj中的name屬性,delattr(x,'y')等同於del x.y
class Car: def __init__(self,c,b): self.color = c self.brand = b def get_car_attr(self,attr_name): '''此方法用於獲取對象的屬性,若是屬性在次對此對象中返回該屬性,若是不在時返回None''' return getattr(self,attr_name,None) c1 =Car("黑色",'Benz') v = c1.get_car_attr('color') if v is None: print("沒有顏色屬性") else: print("顏色是",v)
運算符重載:
什麼是運算符重載
讓自定義的類生成的對象(實例)可以使用運算符進行操做
做用:
一、讓自定義的類的實例像內建對象同樣運行運算符操做
二、讓程序簡潔易讀
三、對自定義的對象,將運算符賦予新的運算規則
算術運算符的重載:
__add__(self, rhs) self + rhs 加法
__sub__(self, rhs) self - rhs 減法
__mul__(self, rhs) self * rhs 乘法
__truediv__(self, rhs) self / rhs 除法
__floordiv__(self, rhs) self // rhs 地板出法
__mod__(self, rhs) self % rhs 求餘
__pow__(self, rhs) self ** rhs 冪運算
注意:rhs(right hands side )右手邊
class MyNumber: def __init__(self,v): self.data = v def __repr__(self): return "MyNumber(%)" % self.data # def myadd(self,other): # v = self.data + other.data # return MyNumber(v) def __add__(self,other): v = self.data + other.data return MyNumber(v) def __sub__(self,other): v = self.data - other.data return MyNumber(v) n1 = MyNumber(100) n2 = MyNumber(200) #n3 = n1.myadd(n2) n3 = n1 + n2 # 等同於n1.__add__(n2) print(n3)#MyNumber(300) n4 = n3 - n2 #等同於n3.__sub__(n2) print(n4) #MyNumber(100)
反向算數運算符的重載:
當左手邊的類型爲內建類型,右手邊爲自定義類型時,要實現運算必須用如下方法重載
__radd__(self, lhs) lhs + self 加法
__rsub__(self, lhs) lhs - self 減法
__rmul__(self, lhs) lhs * self 乘法
__rtruediv__(self, lhs) lhs / self 除法
__rfloordiv__(self, lhs) lhs // self 地板出法
__rmod__(self, lhs) lhs % self 求餘
__rpow__(self, lhs) lhs ** self 冪運算
'''實現兩個自定義列表相加''' class MyList(): def __init__(self,iterable): self.data = iterable def __repr__(self): return 'MyList(%s)' % self.data def __mul__(self,rhs): v = self.data * rhs return MyList(v) def __add__(self,other): v = self.data +other.data return MyList(v) def __rmul__(self,lhs): return MyList(self.data*lhs) def __iadd__(self,other): self.data.extend(other.data)#此出是改變self自己,返回值爲None return self L1 = MyList([1,2,3]) L2 = MyList([4,5,6]) L3 = L1 + L2 #等同於L1.__add__(L2) print(L3)#MyList([1, 2, 3, 4, 5, 6]) L4 = L2 + L1 print(L4)#MyList([4, 5, 6, 1, 2, 3]) L5 = L1 * 2 #等同於L1.__mul__(2) print(L5)#MyList([1, 2, 3, 1, 2, 3]) #(反方算數運算符)當左手邊的類型爲內建類型,右手邊爲自定義類型時,要實現運算必須用一下方法重載 L6 = 2* L1 print(L6)#MyList([1, 2, 3, 1, 2, 3]) #符合算數運算符: L1 += L2 #當沒有__iadd__方法時,等同於調用L1 = L1 + L2,在這裏又從新建立了一個MyList類的對象 print(L1)#當有__iadd__方法時,在這裏不會從新建立了一個MyList類的對象,而是在L1實例上改變
符合賦值運算符的重載:
__iadd__(self, rhs) self += rhs 加法
__isub__(self, rhs) self -= rhs 減法
__imul__(self, rhs) self *= rhs 乘法
__itruediv__(self, rhs) self /= rhs 除法
__ifloordiv__(self, rhs) self //= rhs 地板出法
__imod__(self, rhs) self %= rhs 求餘
__ipow__(self, rhs) self **= rhs 冪運算
比較運算符的重載:
__lt__(self,rhs) self < rhs 小於
__le__(self,rhs) self <= rhs 小於等於
__gt__(self,rhs) self > rhs 大於
__ge__(self,rhs) self >= rhs 大於等於
__eq__(self,rhs) self == rhs 等於
__ne__(self,rhs) self != rhs 不等於
注:比較運算符一般返回True 或 False
lt:less than le:less or equal
gt:greater than gt:gerater or equl
eq:equal ne:not equal
位運算符重載:
__invert__(self) ~ self 取反(一元運算符)
__and__(self,rhs) self & rhs 位與
__or__(self,rhs) self | rhs 位或
__xor__(self,rhs) self ^ rhs 位異或
__lshift__(self,rhs) self << rhs 左移
__rshift__(self,rhs) self >> rhs 右移
反向位運算符重載:
__rand__(self,lhs) lhs & self 位與
__ror__(self,lhs) lhs | self 位或
__rxor__(self,lhs) lhs ^ self 位異或
__rlshift__(self,lhs) lhs << self 左移
__rrshift__(self,lhs) lhs >> self 右移
注:當左手邊的類型爲內建類型,右手邊爲自定義類型時,使用反向位運算符重載
複合賦值位運算符:
__iand__(self,lhs) lhs &= self 位與
__ior__(self,lhs) lhs |= self 位或
__ixor__(self,lhs) lhs ^= self 位異或
__ilshift__(self,lhs) lhs <<= self 左移
__irshift__(self,lhs) lhs >>= self 右移
一元運算符的重載:
__neg__(self) - self 負號
__pos__(self) + self 正號
__invert__(self) ~ self 取反
一元運算符的重載方法:
class 類名:
def __XXX__(self):
....
class MyList(): def __init__(self,iterable): print("__init__被調用") self.data = iterable def __repr__(self): return 'MyList(%r)' % self.data def __neg__(self): '''此方法用來制定 - self 返回的規則''' L = (-x for x in self.data) return MyList(L) L1 = MyList([1,-2,3,-4]) L2 = -L1 print(L2)#MyList([-1, 2, -3, 4])
運算符重載說明:
運算符重載不能改變運算符的優先級
python類名最好用駝峯命名法:
MyList MyRange 大駝峯(全部單詞首字母大寫,其他小寫)
getStudentAge 小駝峯(第一個單詞首字母小寫,其餘首字母大寫)
in /not in 運算符的重載:
重載方法:
def __contanins__(self,e) e in self 成員運算
class MyList(): def __init__(self,iterable): self.data = iterable def __repr__(self): return 'MyList(%r)' % self.data def __contains__(self,e): '''此方法用來實現 in /not in 運算符的重載''' print("__contains__被調用") for x in self.data: if x == e: return True return False L1 = MyList([1,-2,3,-4]) if -2 in L1: print("-2在L1中") else: print("-2不在L中") #當MyList的類內重載了__contains__方法,則not in 也同時可使用(將__contains__方法的返回值取反) if 5 not in L1: print("5不在L1中") else: print("-5在L中")
索引和切片運算符的重載:
__getitem__(self,i) x = self[i] 索引和切片取值
__setitem__(self,i,v) self[i] = v 索引和切片賦值
__delitem__(self,i) del self[i] del 語句刪除索引
做用:讓本身定義的類型的對象可以支持索引和切片操做
slice函數:
做用:用於建立一個Slice切片對象,此對象存儲一個切片的起始值,終止值和步長信息
slice(start,stop=None,step=None) 建立一個切片對象
slice的對象的屬性:
s.start 切片的起始值,默認爲None
s.stop 切片的終止值,默認爲None
s.step 切片的步長,默認爲None
class MyList(): def __init__(self,iterable): print("__init__被調用") self.data = iterable def __repr__(self): return 'MyList(%r)' % self.data def __getitem__(self,i): print("__getitem__被調用,i=",i) if type(i) is not int: raise TpyeError return self.data[i] def __setitem__(self,i,v): self.data[i] = v L1 = MyList([1,-2,3,-4]) v = L1[1] print(v)#-2 L1[1] = 2 print(L1)#MyList([1, 2, 3, -4])
class MyList(): def __init__(self,iterable): print("__init__被調用") self.data = iterable def __repr__(self): return 'MyList(%r)' % self.data def __getitem__(self,i): print("__getitem__被調用,i=",i) if type(i) is int: print("正在作索引操做") elif type(i) is slice: print("正在作切片操做") print("起始值:",i.start) print("終止值:",i.stop) print("步長:",i.step) else: raise KeyError return self.data[i] L1 = MyList([1,-2,3,-4,5,-6]) print(L1[::2])#等同於調用L1[slice(None,None,2)] # __init__被調用 # __getitem__被調用,i= slice(None, None, 2) # 正在作切片操做 # 起始值: None # 終止值: None # 步長: 2 # [1, 3, 5]
類的特殊成員
一、__call__()方法
class Foo: def __init__(self): print("init") def __call__(self): print("call") Foo()()#首先會執行__init__()方法,再執行__call__()方法 obj = Foo()#執行__init__()方法 obj()#執行__call__()方法
metaclass(類的祖宗)
一、Python中一切事物都是對象
二、class Foo:
pass
obj = Foo()
#obj是對象,Foo類的對象
#Foo類也是一個對象,type的對象
三、類都是type類的對象,type(...)
def function(self): print("hello world") #建立一個Foo類繼承object,含有func()方法 Foo = type("Foo",(object,),{'func':function}) obj = Foo() obj.func()
class MyType(type): def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs)#執行父類type的__init__方法 print("MyType的__init__") def __call__(self): print("MyType的__call__") obj = self.__new__(self)#self表明Foo,第三步調用Foo中的new方法,返回Foo的對象 self.__init__(obj)#第四步調用Foo中的__init__方法 class Foo(object,metaclass=MyType):#第一步,編譯器執行到此處是會調用MyType的__init__方法 def __init__(self): print("Foo的__init__") def __new__(cls,*args,**kwargs): print("Foo中的__new__方法") return object.__new__(cls,*args,**kwargs)#真正建立Foo類的對象的地方 obj = Foo()#第二步,在Foo類(MyTpye類的對象)加(),會執行MyType中的__call__方法