python_面向對象

面向對象編程
    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 ()
View Code

    類 和 對象
        類   |      對象      實例
      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,"狗糧")#第二種方法調用實例方法
#對象不能調用類內沒有的方法
View Code

    屬性 attribute(也叫實例變量)
        每一個實例均可以有本身的變量,此變量稱爲實例變量(也叫屬性)
        屬性的使用語法:實例名.屬性名
        賦值規則:
            一、首次爲屬性賦值,則建立此屬性
            二、再次爲屬性賦值,則必改變屬性的綁定關係
        做用:用來記錄對象自身的數據less

class Dog:
    pass
#建立第一個對象
dog1 = Dog()
dog1.kinds = '京巴' #添加屬性kinds
dog1.color = '白色' #添加屬性color
dog1.color = '京巴' #改變屬性的綁定關係
View Code

    實例方法和實例變量(屬性)結合使用編程語言

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("包子")
View Code

    刪除屬性
        用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__方法
View Code

  析構方法:
        語法: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 元錢
View Code

     用於判斷類的函數:
         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
View Code

    類變量的應用案例:
        用類變量來記錄對象的個數測試

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)
View Code

類的文檔字符串:
    類內的一個沒有賦值給任何變量的字符串是類的文檔字符串
    說明:
        一、類的文檔字符串用類的__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)
View Code

類方法 @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())    
View Code

問題:
    一、類方法屬於類
    二、實例方法屬於該類的實例
    三、類內能不能有函數,既不屬於類又不屬於類的實例?
靜態方法 @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
View Code

 繼承 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()
View Code

    顯示調用基類的初始化方法:
        當子類中實現了__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()
View Code

用於類的函數:
    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() #出錯,沒法調用私有方法
View Code

多態 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被調用
View Code

面向對象的編程語言的特徵:
    繼承
    封裝
    多態
    如: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)
View Code

多繼承的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()
View Code
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
View Code

  對象轉化爲字符串函數重寫
        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對象實例
View Code

對象轉字符串函數的重寫方法:
    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)
View Code

內建函數的重寫:
    __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
View Code

布爾測試函數的重寫:
    格式: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
View Code

迭代器(高級):
    什麼是迭代器
        能夠經過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)
View Code

 對象的屬性管理函數:
    一、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)
View Code

運算符重載:
    什麼是運算符重載
        讓自定義的類生成的對象(實例)可以使用運算符進行操做
    做用:
        一、讓自定義的類的實例像內建對象同樣運行運算符操做
        二、讓程序簡潔易讀
        三、對自定義的對象,將運算符賦予新的運算規則


算術運算符的重載:
    __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)
View Code

反向算數運算符的重載:
    當左手邊的類型爲內建類型,右手邊爲自定義類型時,要實現運算必須用如下方法重載
    __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實例上改變
View Code

符合賦值運算符的重載:
    __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])
View Code

運算符重載說明:
    運算符重載不能改變運算符的優先級
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中")    
View Code

索引和切片運算符的重載:
    __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])
View Code
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]
View Code

 類的特殊成員

  一、__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__方法
相關文章
相關標籤/搜索