主頁 > 後端開發 > 13_Python的面向物件編程-類class,物件object,實體instance

13_Python的面向物件編程-類class,物件object,實體instance

2020-09-16 12:25:16 後端開發

1.面向物件概述

    1.類是用來描述物件的工具,把擁有相同屬性和行為的物件分為一組
    2.物件是由類實體化出來的一個具體的物件
        屬性: 物件擁有的名詞,用變數表示
        行為: 物件擁有的動作,用方法表示
    3.面向物件是把一切看成物件,物件和物件之間用方法建立關聯關系
    4.面向程序是一件事怎么一步一步實作,面向物件是一件事情誰去實作
    5.可以用類創建一個或多個此類的物件,類中的變數和方法能被此類所創建的所有物件所共同擁有
    6.面向物件編程語言的特征封裝,繼承,多型
    7.類和物件流程圖: https://www.processon.com/view/link/5ee0e5b5f346fb1ae558f314

類            物件      屬性             方法
車            BYD       E6(京A.88888)    行駛
狗            小京巴     戶籍號:00001     喝水
示例:

2.類的概述

    1.類的創建語法

class 類名(繼承串列):
    """類檔案字串"""
    實體方法(methd) 的定義
    類變數(classVariable) 的定義
    類方法(@classmethod) 的定義
    靜態方法(@staticmethod) 的定義

    2.類名必須是識別符號,即由數字字母下劃線組成且不能以數字開頭和不能是關鍵字,建議用大駝峰命名法,如: WebServer
    3.類名實質上就是變數,它系結一個類實體,屬性是這類事務具有什么樣的特征,方法是這類事務具有什么樣的行為
    4.在Python2中不指定繼承object會定義經典類,Python3中無論是否制定繼承object,都會創建新式類

# Python2中不指定繼承object會創建經典類
class A:
    pass


# Python2中定義新式類
class B(object):
    pass


# Python3中無論是否制定繼承object,都會創建新式類
class C:
    pass
示例:

    5.使用help(__builtins__)可以查看Python中所有的類的繼承派生關系

# 查看類的繼承派生關系
help(__builtins__)
示例:

3.實體與實體化概述

    實體概述:
        1.實體就是有類誕生出的一個物件,實體有自己的作用域或名字空間,可以為該實體添加實體變數
        2.同一個類實體化出的物件是不同的個體,實體可以呼叫類的方法和訪問類中的類變數
    實體化概述:
        1.實體化就是類創建一個物件,并回傳此實體物件的參考關系的程序
        2.語法: obj = 類名([創建傳參串列])  # 創建這個類的實體化物件,并回傳此實體物件的參考關系 []里的形參可省略

class Dog:  # 定義一個狗類
    pass
    
    
dog1 = Dog()  # 用類來創建一個物件用dog1系結
print(id(dog1))  # 列印dog1所在的記憶體地址
dog2 = Dog()  # 創建第二個物件 用dog2系結
print(id(dog2))
# 判斷兩只示例化出來的狗物件是不是同一條狗
print(dog1 is dog2)  # False
示例:

4.類的組成成員: 欄位,方法,靜態屬性

    1.公有靜態欄位: 屬于類在記憶體中只保存一份,類和實體都可以訪問,類內部和派生類中也可以訪問
    2.私有靜態欄位: 屬于類在記憶體中只保存一份,僅類內部可以訪問
    3.公有普通欄位: 屬于物件在每個物件中都要保存一份,實體可以訪問,類內部和派生類中也可以訪問
    4.私有普通欄位: 屬于物件在每個物件中都要保存一份,僅類內部可以訪問
    5.實體方法: 屬于類在記憶體中只保存一份,由物件呼叫,至少一個self引數,實體可以訪問,類內部和派生類中也可以訪問
    6.私有方法: 屬于類在記憶體中只保存一份,僅類內部可以訪問,命名以雙下劃線開頭,沒有引數
    7.類方法: 屬于類在記憶體中只保存一份,由類呼叫,至少一個cls引數,執行類方法時,自動將呼叫該方法的類賦值給cls
    8.靜態方法: 屬于類在記憶體中只保存一份,由類呼叫,無默認引數
    9.靜態屬性: 屬于類在記憶體中只保存一份,實體可以訪問,類內部和派生類中也可以訪問

class ClassMember:
    """此示例闡述類的組成成員"""


    company_name = "x公司"  # 公有靜態欄位(公有靜態變數,類變數),類和實體都可以訪問,類內部和派生類中也可以訪問
    __iphone = "135xxxxxxxx"  # 私有靜態欄位(私有靜態變數,私有類變數),僅類內部可以訪問

    def __init__(self, name, age):  # 初始化方法
        self.name = name  # 公有普通欄位(實體屬性),實體可以訪問,類內部可以訪問,派生類中可以訪問
        self.__age = age  # 私有普通欄位(私有實體屬性),僅類內部可以訪問

    def func1(self):  # 實體方法,至少有一個self引數,實體可以訪問,類內部可以訪問,派生類中可以訪問
        pass

    def __func(self):  # 私有方法,僅類內部可以訪問
        print(666)

    @classmethod  # 類方法
    def class_func(cls):
        """定義類方法,至少有一個cls引數"""
        print("類方法")

    @staticmethod  # 靜態方法
    def static_func():
        """定義靜態方法,無默認引數"""
        print("靜態方法")

    @property  # 靜態屬性,將方法偽裝成屬性來使用
    def prop(self):
        pass
示例:

5.公有靜態欄位與私有靜態欄位

    1.公有靜態欄位概述(公有靜態變數,公有類變數)
        1.類變數類可以通過類名.來訪問,類內部和派生類中也可以訪問
        2.類變數是類的屬性,此屬性屬于類,不屬于此類創建的實體
        3.類變數可以通過此類實體化物件訪問,可以通過實體的 '__class__'屬性間接修改

class Human:
    total_count = 0  # 類變數, 用于記錄物件的個數
    
    
print(Human.total_count)
h1 = Human()
print(h1.total_count)  # 0  # 不會出錯
Human.total_count = 1  # 修改類變數
h1.total_count = 2  # 添加了自己的實體屬性total_count
h1.__class__.total_count = 3  # 間接修改類變數
示例1:
class Human:
    total_count = 0  # 類變數,用于記錄物件的個數
    def __init__(self, name):
        self.name = name
        self.__class__.total_count += 1  # 人數加1
        print(name, "物件創建")

    def __del__(self):
        self.__class__.total_count -= 1  # 總人數減1


print("當前物件的個數是:", Human.total_count)  # 0
h1 = Human("張飛")
h2 = Human("趙云")
print("當前物件的個數是:", Human.total_count)  # 2
del h2  # 或 h2 = None
print("當前物件的個數是:", Human.total_count)  # 1
示例2:
class C:
    name = "公有靜態欄位"
    def func(self):
        print(C.name)


class D(C):
    def show(self):
        print(C.name)


C.name  # 類訪問
obj = C()
obj.func()  # 類內部可以訪問
obj_son = D()
obj_son.show()  # 派生類中可以訪問
示例3:

    2.私有靜態欄位(私有靜態變數,私有類變數)
        1.用戶在創建類是可以在屬性名前加雙下劃線來宣告該屬性只屬于類所有,僅類內部可以訪問
        2.私有類變數不能被外界的實體物件直接訪問,也不可以通過該類直接訪問,不可在派生類中訪問
        3.私有類變數可以通過_類名__變數名來間接訪問

class C:
    __name = "私有靜態欄位"

    def func(self):
        print(C.__name)


class D(C):
    def show(self):
        print(C.__name)


# C.__name  # 不可在外部訪問
obj = C()
# obj.__name  # 不可在外部訪問
obj._C__name  # 可以通過_類名__屬性名來間接訪問
obj.func()  # 類內部可以訪問
obj_son = D()
obj_son.show()  # 不可在派生類中訪問
示例:

    3.變數的賦值規則: 首次為變數賦值則創建此變數,再次為變數賦值則改變變數的系結關系

    4.在定義變數時如果不確定設定什么初始值,可以設定為None

    5.洗掉變數del陳述句,語法: del 類名.變數名

    6.類名.變數查找順序: 先從本類空間找,如果找不到,再從父類找...

    7.可以通過類的__dict__方法查看類的所有屬性所在的字典

    8.可以通過dir函式查看類的所有屬性和方法

6.公有普通欄位與私有普通欄位

    1.公有普通欄位概述(公有實體屬性,公有實體變數)
        1.每個實體可以有自己的屬性,實體屬性的使用語法: 實體.屬性名
        2.實體屬性: 物件可以訪問,類內部和派生類中也可以訪問

class C:
    def __init__(self):
        self.foo = "公有普通欄位"

    def func(self):
        print(self.foo)  # 類內部訪問


class D(C):
    def show(self):
        print(self.foo)  # 派生類中訪問


obj = C()
obj.foo  # 通過物件訪問
obj.func()  # 類內部訪問
obj_son = D()
obj_son.show()  # 派生類中訪問
示例1:
class Dog:
    
    def __init__(self):
        self.name = None
        self.color = None
    
    
dog1 = Dog()
dog1.kinds = "京巴"  # 為dog1系結的實體添加kinds屬性
dog1.color = "白色"  # 添加屬性
print(dog1.kinds, dog1.color)  # 訪問屬性
dog1.color = '黃色' # 修改dog1.color 的系結關系
print(dog1.color)
示例2:

    2.私有普通欄位概述(私有實體屬性,私有實體變數)
        1.每個實體可以有自己的私有屬性,稱為私有實體屬性或私有實體變數,使用語法: 實體.類中的參考方法名
        2.私有實體屬性: 僅類內部可以訪問,但可以通過_類名__屬性名來間接訪問

class C:
    def __init__(self):
        self.__foo = "私有欄位"

    def func(self):
        print(self.foo)  # 類內部訪問

class D(C):
    
    def show(self):
        print(self.foo)  # 派生類中訪問

obj = C()
obj.__foo  # 通過物件訪問會報錯
obj.func()  # 類內部可以訪問
obj_son = D()
obj_son.show()  # 派生類中訪問會報錯
示例1:
class Women:
    def __init__(self, name):
        self.name = name
        self.__age = 18

    def secret(self):
        print("%s的年齡是%d" % (self.name, self.__age))


xiaomei = Women("小美")
# print(xiaomei.__age)  # 私有屬性不能被外界的實體物件直接訪問
xiaomei.secret()  # 在物件內部的方法可以直接訪問物件的私有屬性
print(xiaomei._Women__age)  # 私有屬性可以通過_類名__屬性名來間接訪問
xiaomei.__dict__  # {'name': '小美', '_Women__age': 18}
dir(xiaomei)[0:3]  # ['_Women__age', '__class__', '__delattr__']
示例2:

    3.屬性的賦值規則: 首次為屬性賦值則創建此屬性,再次為屬性賦值則改變屬性的系結關系

    4.在定義屬性時如果不確定設定什么初始值,可以設定為None

    5.洗掉屬性del陳述句,語法: del 物件.屬性名

class Student:
    pass


stu = Student()
stu.name = 'xiaozhang'  # 創建屬性
print(stu.name)
del stu.name  # 洗掉此屬性
print(stu.name)  # 屬性錯誤,因為屬性已經不存在了
示例:

    6.物件.屬性查找順序: 先從物件空間找,如果找不到,再從類空間找,再找不到,再從父類找...

    7.可以通過物件的__dict__方法查看物件所有屬性所在的字典

    8.可以通過dir函式查看物件的所有屬性和方法

7.實體方法與私有方法

    1.實體方法概述
        1.實體方法的實質是函式,是定義在類內的函式,用于描述一個物件的行為,讓此型別的全部物件都擁有相同的行為
        2.實體方法至少有一個self引數代表呼叫這個方法的實體,宣告該方法是實體方法
        3.實體方法物件可以訪問,類內部和派生類中也可以訪問
        4.實體方法的呼叫語法:
            實體.實體方法名(呼叫引數)
            類名.實體方法名(實體, 呼叫引數)

class C:
    def __init__(self):
        pass
    
    def add(self):
        print("this is add")


class D(C):
    def show(self):
        print("this is show")
        
    def func(self):
        self.show()


obj = D()
obj.show()  # 通過物件訪問
obj.func()  # 類內部訪問
obj.add()  # 派生類中訪問
D.func(obj)  # 類名呼叫
示例:

    2.私有方法概述
        1.用戶在創建類是可以在方法名前加雙下劃線(__方法名)來宣告該屬性只屬于類所有
        2.私有方法不能被外界的實體物件直接訪問
        3.用戶自定義的私有方法可以通過_類名__方法名來間接訪問

class Women:
    def __init__(self, name):
        self.name = name
        self.__age = 18

    def __secret(self):
        print("%s的年齡是%d" % (self.name, self.__age))


xiaomei = Women("小美")
# xiaomei.__secret()  # 私有方法不能被外界的實體物件直接訪問
xiaomei._Women__secret()  # 私有方法可以通過_類名__方法名來間接訪問
xiaomei.__dict__  # {'name': '小美', '_Women__age': 18}
dir(xiaomei)[0:3]  # ['_Women__age', '_Women__secret', '__class__']
示例:

    3.洗掉方法del陳述句,語法: del 類名.方法名

    4.類名.方法查找順序: 先從本類空間找,如果找不到,再從父類找...

    5.可以通過物件的__dict__方法查看物件所有屬性所在的字典

    6.可以通過dir函式查看物件的所有屬性和方法

8.類方法與靜態方法和靜態屬性(@classmethod, @staticmethod, @property)

1.類方法 classmethod

        類方法概述:
            1.類方法是操作類的方法,類方法屬于類,不屬于該類創建的物件
            2.類方法需要使用 @classmethod 裝飾器定義,第一個引數用來系結類,約定寫為cls
            3.類和物件實體都可以呼叫類方法,類方法不能訪問此類創建的物件的屬性
            4.類方法不用物件命名空間中的內容,而是用到了類命名空間中的變數(靜態屬性),或者類方法,靜態方法

class A:
    v = 0  # 類變數
    @classmethod
    def get_v(cls):  # 此方法是類方法
        return cls.v
        
        
a = A()
a.get_v()  # 0
A.get_v()  # 0
a.__dict__  # {}
示例1:
class Goods:
    __discount = 0.8
    def __init__(self, price):
        self.__price = price

    @property
    def price(self):
        return self.__price * Goods.__discount

    @classmethod
    def change_discount(cls, num):
        cls.__discount = num


# 商場的程式
apple = Goods(10)
banana = Goods(15)
print(apple.price,banana.price)
Goods.change_discount(1)
print(apple.price,banana.price)
示例2:

2.靜態方法 staticmethod

        靜態方法概述:
            1.靜態方法是定義在類的內部的函式,此函式作用域是類的內部
            2.靜態方法需要使用@staticmethod 裝飾器定義,定義上與普通函式的定義相同,不需要傳入self和cls
            3.靜態方法只能憑借該類和實體來呼叫,不能訪問類變數和實體變數
            4.如果一個類里面的方法既不需要用到self中的資源,也不用cls中的資源,就將這個方法定義成一個靜態方法

class A:
    @staticmethod
    def myadd(a, b):  # 此方法是靜態方法
        return a + b
        
        
print(A.myadd(100, 200))  # 300
a = A()
print(a.myadd(300, 400))  # 300
示例1:
# 裝飾登錄功能
class Person:
    @staticmethod
    def login():  # 動詞 動作 屬于某一個物件
        pass


class Student(Person):
    pass


class Manager(Person):
    pass


class Course:
    pass


class Classes:
    pass
示例2:

3.靜態屬性 property

        靜態屬性概述:
            1.將方法偽裝成一個靜態屬性,代碼上沒有什么提升只是更合理,靜態屬性本質就是實作了 get,set,delete 三種方法
            2.靜態屬性需要使用 @property 裝飾器定義,只和實體物件系結既可以訪問實體屬性也可以訪問類的屬性
            3.property的構造方法中有個四個引數
                1.第一個引數是方法名,呼叫 物件.屬性 時自動觸發執行方法
                2.第二個引數是方法名,呼叫 物件.屬性 = XXX 時自動觸發執行方法
                3.第三個引數是方法名,呼叫 del 物件.屬性 時自動觸發執行方法
                4.第四個引數是字串,呼叫 物件.屬性.__doc__ 時此引數是該屬性的描述資訊
            4.@方法名.setter裝飾器:
                修改property裝飾的屬性時會被呼叫這個裝飾器裝飾的方法
                除了self外還有一個引數是被修改的值
            5.@方法名.deleter裝飾器:
                當要洗掉被property裝飾的屬性時會被呼叫這個裝飾器的方法
                實際不會洗掉被property裝飾的方法,而是在執行'del 類名.屬性'洗掉操作時執行這個裝飾器的方法
            6.定義property屬性有兩種方式: 在方法上應用裝飾器和在類中定義值為property物件的類屬性

# property屬性定義方式: 類中定義值為property物件的類屬性
class Foo: 
    def get_bar(self):
        return 'Tom'

    # 必須兩個引數
    def set_bar(self, value): 
        return return 'set value' + value

    def del_bar(self):
        return 'Tom'

    BAR = property(get_bar, set_bar, del_bar, 'description')


obj = Foo()

obj.BAR  # 自動呼叫第一個引數中定義的方法: get_bar
obj.BAR = "Cat"  # 自動呼叫第二個引數中定義的方法: set_bar方法,并將"Cat"當作引數傳入
del Foo.BAR  # 自動呼叫第三個引數中定義的方法: del_bar方法
obj.BAE.__doc__  # 自動獲取第四個引數中設定的值: description
示例1:
# property屬性定義方式: 在方法上應用裝飾器
class Person:
    def __init__(self, name, age):
        self.name = name
        if type(age) is int:
            self.__age = age
        else:
            print('你輸入的年齡的型別有誤,請輸入數字')
            
    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, a1):
        '''判斷,你修改的年齡必須是數字'''
        if type(a1) is int:
            self.__age = a1
        else:
            print('你輸入的年齡的型別有誤,請輸入數字')

    @age.deleter
    def age(self):
        del self.__age


p1 = Person('帥哥', 20)
print(p1.age)  # 20
print(p1.__dict__)  # {'name': '帥哥', '_Person__age': 20}
p1.age = 23
print(p1.age)  # 23
del p1.age
示例2:
# property屬性定義方式: 在方法上應用裝飾器
class Money(object):
    def __init__(self):
        self.__money = 0

    # 使用裝飾器對money進行裝飾,那么會自動添加一個叫money的屬性,當呼叫獲取money的值時呼叫裝飾的方法
    @property
    def money(self):
        return self.__money

    # 使用裝飾器對money進行裝飾,當對money設定值時,呼叫裝飾的方法
    @money.setter
    def money(self, value):
        if isinstance(value, int):
            self.__money = value
        else:
            print("error:不是整型數字")


a = Money()
a.money = 100
print(a.money)


# property屬性定義方式: 在方法上應用裝飾器
    class Money(object):
        def __init__(self):
            self.__money = 0

        def getMoney(self):
            return self.__money

        def setMoney(self, value):
            if isinstance(value, int):
                self.__money = value
            else:
                print("error:不是整型數字")

        # 定義一個屬性,當對這個money設定值時呼叫setMoney,當獲取值時呼叫getMoney
        money = property(getMoney, setMoney)

    a = Money()
    a.money = 100  # 呼叫setMoney方法
    print(a.money)  # 呼叫getMoney方法
示例3:
# property屬性定義方式: 在方法上應用裝飾器,實作型別檢測功能
class People:
    def __init__(self, name):
        self.name = name  # 實體化就觸發property

    @property
    def name(self):
        # return self.name  # 無限遞回
        print('get------>')
        return self.DouNiWan

    @name.setter
    def name(self, value):
        print('set------>')
        if not isinstance(value, str):
            raise TypeError('必須是字串型別')
        self.DouNiWan = value

    @name.deleter
    def name(self):
        print('delete------>')
        del self.DouNiWan


p1 = People('echo')  # self.name實際是存放到self.DouNiWan里
p1.name = 1
示例4:
# property屬性定義方式: 在方法上應用裝飾器,驗證@deleter不會洗掉被property裝飾的方法
class A:
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, new_name):
        if type(new_name) is str:
            self.__name = new_name

    @name.deleter
    def name(self):
        def self.__name


a = A("Ccoc")
print(a.name)
a.name = "echo"
del a.name  # 看似是洗掉了name屬性,實際是洗掉了__name私有屬性
# print(a)
示例5:
# property屬性定義方式: 在方法上應用裝飾器,讓呼叫看起來更加合理
class Pager:
    def __init__(self, current_page):
        # 用戶當前請求的頁碼(第一頁,第二頁...)
        self.current_page = current_page
        # 每頁默認顯示10條資料
        self.per_items = 10 

    @property
    def start(self):
        val = (self.current_page - 1) * self.per_items
        return val

    @property
    def end(self):
        val = self.current_page * self.per_items
        return val


p = Pager(1)
p.start  # 就是起始值,即: m
p.end  # 就是結束值,即: n
示例6:
# property屬性定義方式: 在方法上應用裝飾器,取代getater和seatter以及delattr方法
class Goods(object):

    def __init__(self):
        # 原價
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    @property
    def price(self):
        # 實際價格 = 原價 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    @price.setter
    def price(self, value):
        self.original_price = value

    @price.deleter
    def price(self):
        del self.original_price

obj = Goods()
obj.price  # 獲取商品價格
obj.price = 200  # 修改商品原價
del obj.price  # 洗掉商品原價
示例7:
# property屬性定義方式: 使用類屬性的方式創建property屬性改寫示例7
class Goods(object):

    def __init__(self):
        # 原價
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    def get_price(self):
        # 實際價格 = 原價 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    def set_price(self, value):
        self.original_price = value

    def del_price(self):
        del self.original_price

    PRICE = property(get_price, set_price, del_price, '價格屬性描述...')

obj = Goods()
obj.PRICE  # 獲取商品價格
obj.PRICE = 200  # 修改商品原價
del obj.PRICE  # 洗掉商品原價
示例8:

    4.靜態方法,類方法,靜態屬性綜合示例

class Room(object):
    tag = 1

    def __init__(self, wight, length):
        self.wight = wight
        self.length = length

    @property
    def car_area(self):
        return self.length * self.wight + self.tag

    @classmethod
    def tell_info(cls):
        print(cls)
        print("-->", cls.tag)

    @staticmethod
    def run(a, b):
        print("%s %s 正在跑步" % (a, b))


# 靜態屬性: 將類的函式屬性@property裝飾后,是物件以資料屬性的方式呼叫
# 只和實體物件系結-->即可以訪問實體屬性也可以訪問類的屬性
p1 = Room(10, 20)
print("類屬性", p1.tag)
print("實體物件呼叫靜態屬性", p1.car_area)

# 類方法: 將類的函式屬性@classmethod裝飾后,不用創建實體物件,呼叫類的函式屬性
# 只和類系結-->可以訪問類屬性,不能訪問實體屬性
Room.tell_info()

# 靜態方法: 將類的函式屬性@staticmethod裝飾后,不創建和創建實體物件,都可以呼叫類的函式屬性
# 即不和類系結也不和實體物件系結-->不能訪問類屬性,也不能訪問實體屬性,是類的工具包
Room.run("co1", "co2")
p2 = Room(20, 20)
p2.run("co3", "co4")
示例:

    5.Django框架中應用了property屬性

class WSGIRequest(http.HttpRequest):
    def __init__(self, environ):
        script_name = get_script_name(environ)
        path_info = get_path_info(environ)
        if not path_info:
            # Sometimes PATH_INFO exists, but is empty (e.g. accessing
            # the SCRIPT_NAME URL without a trailing slash). We really need to
            # operate as if they'd requested '/'. Not amazingly nice to force
            # the path like this, but should be harmless.
            path_info = '/'
        self.environ = environ
        self.path_info = path_info
        self.path = '%s/%s' % (script_name.rstrip('/'), path_info.lstrip('/'))
        self.META = environ
        self.META['PATH_INFO'] = path_info
        self.META['SCRIPT_NAME'] = script_name
        self.method = environ['REQUEST_METHOD'].upper()
        _, content_params = cgi.parse_header(environ.get('CONTENT_TYPE', ''))
        if 'charset' in content_params:
            try:
                codecs.lookup(content_params['charset'])
            except LookupError:
                pass
            else:
                self.encoding = content_params['charset']
        self._post_parse_error = False
        try:
            content_length = int(environ.get('CONTENT_LENGTH'))
        except (ValueError, TypeError):
            content_length = 0
        self._stream = LimitedStream(self.environ['wsgi.input'], content_length)
        self._read_started = False
        self.resolver_match = None

    def _get_scheme(self):
        return self.environ.get('wsgi.url_scheme')

    def _get_request(self):
        warnings.warn('`request.REQUEST` is deprecated, use `request.GET` or '
                      '`request.POST` instead.', RemovedInDjango19Warning, 2)
        if not hasattr(self, '_request'):
            self._request = datastructures.MergeDict(self.POST, self.GET)
        return self._request

    @cached_property
    def GET(self):
        # The WSGI spec says 'QUERY_STRING' may be absent.
        raw_query_string = get_bytes_from_wsgi(self.environ, 'QUERY_STRING', '')
        return http.QueryDict(raw_query_string, encoding=self._encoding)

    # ############### 看這里看這里  ###############
    def _get_post(self):
        if not hasattr(self, '_post'):
            self._load_post_and_files()
        return self._post

    # ############### 看這里看這里  ###############
    def _set_post(self, post):
        self._post = post

    @cached_property
    def COOKIES(self):
        raw_cookie = get_str_from_wsgi(self.environ, 'HTTP_COOKIE', '')
        return http.parse_cookie(raw_cookie)

    def _get_files(self):
        if not hasattr(self, '_files'):
            self._load_post_and_files()
        return self._files

    # ############### 看這里看這里  ###############
    POST = property(_get_post, _set_post)

    FILES = property(_get_files)
    REQUEST = property(_get_request)
示例:

9.作用于類的內置函式(isinstance issubclass object super vars type)

1.isinstance函式

        isinstance(obj, class_or_tuple):
            回傳這個物件是否是某個類的物件,或者某些類中的一個類的物件,如果是則回傳True,否則回傳False

class Foo(object):
     pass
  

obj = Foo()
isinstance(obj, Foo)  # True
isinstance(1, int)  # True
isinstance("", (int, str, list))  # # True
示例:

2.issubclass函式

        issubclass(cls, class_or_tuple):
            判斷一個類是否是繼承自其它的類,如果此類cls是class或tuple中的一個派生子類則回傳True,否則回傳False

class A:
    pass
    
    
class B(A):
    pass
    
    
class C(B):
    pass
    
class D(B):
    pass
    
    
issubclass(B, A)  # True
issubclass(C, B)  # True
issubclass(D, C)  # False
issubclass(C, (int, str))  # False
示例:

3.object函式

        object函式概述:
            1.object類是Python中所有類的基類,如果定義一個類時沒有指定繼承哪個類,則默認繼承object類
            2.object沒有定義__dict__所以不能對object類實體物件嘗試設定屬性
            3.object函式回傳一個新的無特征物件,obj = object()

class A:
    pass


# 默認繼承object類
print(issubclass(A,object))  # True
# object類定義了所有類的一些公共方法
print(dir(object)[0:5])
# ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__']

# object函式回傳一個新的無特征物件
obj = object()
type(obj)  # object
print(obj)  # <object object at 0x0000000003E89EF0>
示例1:
# 定義一個類A
class A:
    pass


a = A()
a.name = 'li'  # 能設定屬性
 
b = object()
b.name = 'wang'  # 不能設定屬性
"""執行結果
    AttributeError                            Traceback (most recent call last)
    <ipython-input-23-fae4aa8bc37b> in <module>
          7
          8 b = object()
    ----> 9 b.name = 'wang' # 不能設定屬性

    AttributeError: 'object' object has no attribute 'name'
"""
示例2:

4.super函式

        super函式概述:
            1.回傳超類的實體,用超類實體來呼叫其自身的方法,super()就是使用super類創建出來的物件
            2.當子類實作了__init__方法后,父類的__init__方法將被覆寫,不再會主動呼叫父類的__init__方法
            3.當子類實作了__init__方法后,會引起父類的屬性得不到初始化,需要父類初始化屬性必須要在子類中呼叫super函式
            4.super(type, obj): 回傳系結超類的實體(要求obj必須為type型別的實體)
            5.super(): 回傳系結超類的實體,等同于super(__class__, 實體的第一個引數), 且必須在方法內呼叫

# 此示例示意用super函式訪問父類的覆寫方法
class A:
    def work(self):
        print("A類的work方法被呼叫")

class B(A):
    def work(self):
        print("B類的work方法被呼叫")

    def doworks(self):
        # self.work()  # 呼叫B類的方法
        super(B, self).work()  # 呼叫超類的方法
        super().work()  # Python推薦的呼叫超類的呼叫方法
        # super(__class__, self).work()  # 一樣會呼叫超類的方法

b = B()
b.work()  # B類的work方法被呼叫
print("-----以下用b呼叫覆寫版本的方法----")
# A.work(b)  # A類的work方法被呼叫
super(B, b).work()
b.doworks()
示例1:
# 此示例示意顯式呼叫基類的初始化方法
class Human:
    def __init__(self, n, a):
        self.name = n
        self.age = a
        print("Human類的 __init__被呼叫")

    def show_info(self):
        print("姓名:", self.name)
        print("年齡:", self.age)


class Student(Human):
    """學生類"""
    def __init__(self, n, a, s=0):
        super().__init__(n, a)  # 顯式呼叫基類的初始化方法
        self.score = s
        print("Student類的 __init__被呼叫")

    def show_info(self):
        super().show_info()
        print("成績:", self.score)


s1 = Student('coco', 20)
s1.show_info()
示例2:

5.vars函式

        vars() 函式回傳物件object的屬性和屬性值的字典物件

print(vars())
"""
    {'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', 
    '__doc__': None, '__package__': None}
"""
示例1:
class Runoob:
    a = 1


print(vars(Runoob))  # {'a': 1, '__module__': '__main__', '__doc__': None}
runoob = Runoob()
print(vars(runoob))  # {}
示例2:

6.type函式(type元類)

        type元類概述:
            1.type元類是獲取該物件從屬于的類
            2.Python原則是: 一切皆物件,其實類也可以理解為'物件',而type元類又稱作構建類
            3.Python中大多數內置的類(包括object)以及自己定義的類,都是由type元類創造的
            4.而type類與object類之間的關系比較獨特:
                1.object是type類的實體,而type類是object類的子類
                2.這種關系比較神奇無法使用python的代碼表述,因為定義其中一個之前另一個必須存在

# type(obj)回傳物件的類
class A:
    pass


a = A()
type(a)  # __main__.A
示例:

10.屬性管理內置函式(反射函式)-getattr, hasattr, setattr, delattr

    反射概述: 從某個指定的命名空間中,用字串資料型別的變數名來獲取變數的值
    getattr(obj, name[, default]):
        從一個物件得到物件的屬性;getattr(x, 'y') 等同于x.y
        當屬性不存在時,如果給出default引數,則回傳default,如果沒有給出default 則產生一個AttributeError錯誤
    hasattr(obj, name):
        用給定的name回傳物件obj是否有此屬性,此種做法可以避免在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 Student:
    ROLE = 'STUDENT'
    @classmethod
    def check_course(cls):
        print('查看課程了')

    @staticmethod
    def login():
        print('登錄')
        
        
# 反射查看屬性
print(Student.ROLE)  # STUDENT
print(getattr(Student, 'ROLE'))  # STUDENT

# 反射呼叫方法
getattr(Student, 'check_course')()  # 查看課程了
getattr(Student, 'login')()  # 登錄

num = input('>>>')  # login
if hasattr(Student, num):
    getattr(Student, num)()  # 登錄
示例1:
# 對實體化物件的反射-拿屬性,方法
class Foo:
    f = '類的靜態變數'
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say_hi(self):
        print('hi,%s' % self.name)

obj = Foo('egon', 73)

# 檢測是否含有某屬性
print(hasattr(obj, 'name'))
print(hasattr(obj, 'say_hi'))

# 獲取屬性
n = getattr(obj, 'name')
print(n)
func = getattr(obj, 'say_hi')
func()

print(getattr(obj, 'aaaaaaaa', '不存在'))  # 報錯

# 設定屬性
setattr(obj, 'sb', True)
setattr(obj, 'show_name', lambda self: self.name + 'sb')
print(obj.__dict__)
print(obj.show_name(obj))

# 洗掉屬性
delattr(obj, 'age')
delattr(obj, 'show_name')
delattr(obj, 'show_name111')  # 不存在,則報錯

print(obj.__dict__)
示例2:
# 反射當前模塊成員-拿自己的變數名
import sys


def s1():
    print('s1')


def s2():
    print('s2')


this_module = sys.modules[__name__]

hasattr(this_module, 's1')
getattr(this_module, 's2')
示例3:
# 匯入其他模塊,利用反射-拿模塊中的方法
"""程式目錄
        module_test.py
        index.py
"""
# module_test.py中的代碼
def test():
    print('from the test')
    


# index.py中的代碼
import module_test as obj

# obj.test()
print(hasattr(obj, 'test'))
getattr(obj, 'test')()
示例4:
# 反射的應用
class User:
    def login(self):
        print('歡迎來到登錄頁面')
    
    def register(self):
        print('歡迎來到注冊頁面')
    
    def save(self):
        print('歡迎來到存盤頁面')

user = User()
while 1:
    choose = input('>>>').strip()
    if hasattr(user, choose):
        func = getattr(user, choose)
        func()
    else:
        print('輸入錯誤...')
示例5:
# 四個反射函式綜合運用
class BlackMedium:
    feature = 'Ugly'
    def __init__(self, name, addr):
        self.name = name
        self.addr = addr

    def sell_house(self):
        print('%s 賣房子' %self.name)

    def rent_house(self):
        print('%s 出租' %self.name)


b1 = BlackMedium('桃園', 'xx區xx路')

# 檢測是否含有某屬性
print(hasattr(b1, 'name'))
print(hasattr(b1, 'sell_house'))

# 獲取屬性
n = getattr(b1, 'name')
print(n)
func = getattr(b1, 'rent_house')
func()

# getattr(b1, 'a')  # 報錯
print(getattr(b1, 'a', '不存在'))

# 設定屬性
setattr(b1, 'sb', True)
setattr(b1, 'show_name', lambda self: '景秀' + self.name)
print(b1.__dict__)
print(b1.show_name(b1))

# 洗掉屬性
delattr(b1, 'addr')
delattr(b1, 'show_name')
# delattr(b1, 'show_name111')  # 不存在則報錯
print(b1.__dict__)
示例6:

11.函式與方法的區別

    1.函式的是顯式傳遞資料的,是操作引數傳入的資料,與物件無關
    2.方法中的資料則是隱式傳遞的,方法可以操作類內部的資料,和物件有關聯
    3.列印物件名稱可以確定物件是函式還是方法

def func():
    pass

print(func)  # <function func at 0x10f65c170>


class A:
    def func(self):
        pass
    

print(A.func)  # <function A.func at 0x10f67c0e0>
obj = A()
print(obj.func)  # <bound method A.func of <__main__.A object at 0x10f692250>>
示例:

    4.模塊驗證物件是函式還是方法

from types import FunctionType
from types import MethodType

def func():
    pass


class A:
    def func(self):
        pass


obj = A()
print(isinstance(func, FunctionType))  # True
print(isinstance(A.func, FunctionType))  # True
print(isinstance(obj.func, FunctionType))  # False
print(isinstance(obj.func, MethodType))  # True
示例:

    5.靜態方法其實是函式

from types import FunctionType
from types import MethodType

class A:
    
    def func(self):
        pass
    
    @classmethod
    def func1(cls):
        pass
    
    @staticmethod
    def func2():
        pass


obj = A()
# 靜態方法其實是函式
print(isinstance(A.func2, FunctionType))  # True
print(isinstance(obj.func2, FunctionType))  # True
print(isinstance(obj.func1, FunctionType))  # False
示例:

12.雙下屬性

1.類的檔案字串屬性 __doc__

        __doc__屬性: 是類的描述資訊,無法被子類繼承

class Demo:
    """測驗類"""
    pass


Demo.__doc__  # '測驗類'
示例1:
class Foo:
    """描述資訊"""
    pass


class Bar(Foo):
    pass


print(Bar.__doc__)  # 該屬性無法繼承給子類
示例2:

2.類的字典屬性 __dict__

        __dict__屬性: 可以查詢類中的所有屬性和方法

class A:
    a = 1
    def add():
        pass


A.__dict__
"""執行結果
    mappingproxy({'__module__': '__main__',
                  'a': 1,
                  'add': <function __main__.A.add()>,
                  '__dict__': <attribute '__dict__' of 'A' objects>,
                  '__weakref__': <attribute '__weakref__' of 'A' objects>,
                  '__doc__': None})
"""
示例:

3.類的名稱屬性 __name__

class Demo:
    """測驗類"""
    pass


Demo.__name__  # 'Demo'
示例:

4.類的記錄基類屬性 __base__, __bases__

        __base__屬性: 用來記錄此類的基類,回傳一個字串
        __bases__屬性: 用來記錄此類的基類,回傳一個元祖

class A:
    pass
    

class B(A):
    pass
    

B.__base__  # __main__.A
B.__bases__  # (__main__.A,)

A.__base__  # object
A.__bases__  # (object,)
type.__base__  # object
str.__bases__  # (object,)
示例:

5.類的限定實體化物件的屬性 __slots__

        __slots__屬性概述
            1.是一個類變數,變數值可以是串列,元祖,或者可迭代物件,也可以是一個字串(意味著所有實體只有一個固定的屬性)
            2.使用點來訪問屬性本質就是在訪問類或者物件的__dict__屬性字典(類的字典是共享的,而每個實體的是獨立的)
            3.字典會占用大量記憶體,如果類的屬性很少但卻有很多實體,為了節省記憶體可以使用__slots__取代實體的__dict__
            4.含有 __slots__ 屬性的類所創建的物件沒有__dict__字典,統一歸__slots__管理,有利于節省記憶體

class Student:
    # 限定此的類創建的物件只能有name和age兩個屬性
    __slots__ = ['name', 'age']

    def __init__(self, n, a):
        self.name = n
        self.age = a
s1 = Student("小張", 20)
# s1.Age = 21  # 此時是錯寫了age為Age, 會報錯
# print(s1.__dict__) # 出錯,因為沒有__dict__字典
示例:
class Foo2:
    """檔案描述"""
    # __slost__取代了類的__dict__使實體化除的屬性沒有__dict__方法
    __slots__ = ["name", "age"]


class Foo3(Foo2):
    def __del__(self):
        print("回收實體時觸發")

    def __call__(self, *args, **kwargs):
        print("__call__方法讓實體物件可以加()執行")


f3 = Foo2
print("f3", f3.__slots__)

# __doc__記錄類的檔案描述資訊
print(Foo2.__doc__)  # 檔案描述

# __doc__無法被子類繼承,因為子類一旦定義就有屬于自己的__doc__
print(Foo3.__doc__)  # None
print(Foo3.__dict__)

# __module__查看f3來自于哪個模塊
print(f3.__module__)  # __main__
# __class__查看f3來自于哪個類
print(f3.__class__)  # <class 'type'>

f3 = Foo3()  # <class 'type'>
f3()  # __call__方法讓實體物件可以加()執行

# __del__解構式,會在回收實體時觸發
del f3  # 回收實體時觸發
示例:

6.實體的預置屬性 __dict__, __class__

        __dict__屬性: 用于系結一個存盤此實體自身變數的字典
        __class__ 屬性: 用于系結創建此實體的類,表示當前操作的物件的類是什么

class Dog:
    pass
    
    
dog1 = Dog()
print(dog1.__dict__)  # {}
dog1.color = "白色"
print(dog1.__dict__)  # {'color': '白色'}
print(dog1.__class__)  # <class '__main__.Dog'>
示例:

7.實體的隸屬屬性 __module__

        __module__屬性: 表示當前操作的物件在那個模塊

# 模塊 My_Module 中的代碼
class C:
    def __init__(self):
        self.name = "Cat"
# 主模塊中的代碼
from My_Module import C


obj = C()
# 輸出obj物件所在的模塊
print(obj.__module__)  # My_Module
# 即輸出obj物件所在的類
print(obj.__class__)  # My_Module.C
示例:

13.雙下方法

1.構造方法 __new__

        構造方式概述:
            1.程序: 開辟一個屬于物件的空間,把對象的空間傳給self后執行init,最后將這個物件的空間回傳給呼叫者
            2.new方法在實體化之后,__init__ 之前先執行new來創建一塊空間
            3.當創建的類沒有new方法時,會呼叫object的new方法

class Single:
    def __new__(cls, *args, **kwargs):
        # print('在new方法里')
        obj = object.__new__(cls)
        print('在new方法里', obj)
        return obj

    def __init__(self):
        print('在init方法里', self)


# 實體化時,__new__構造方法先呼叫,接著__init__初始化方法呼叫
obj = Single()
"""執行結果
    在new方法里 <__main__.Single object at 0x000000000525EDD8>
    在init方法里 <__main__.Single object at 0x000000000525EDD8>
"""
示例:

2.初始化方法 __init__

        初始化方法概述:
            1.初始化方法名必須為 __init__ 不可改變,是對新創建的物件添加屬性等必須的資源
            2.初始化方法會在建構式創建實體后自動呼叫, 且將實體自身通過第一個引數 self 傳入 __init__ 方法
            3.建構式的實參將通過 __init__ 方法的引數串列傳到 __init__ 方法中
            4.初始化方法內如果需要 return 陳述句回傳則必須回傳 None
            5.語法形式:
                class 類名:

                    def __init__(self[, 引數串列]):  # []代表其中內容可省略
                        陳述句塊

# 此示例示意初始化方法的定義方法和呼叫程序
class Car:
    """小汽車類"""
    def __init__(self, c, b, m):
        self.color = c  # 顏色
        self.brand = b  # 品牌
        self.model = m  # 型號
        self.wheel = 4
        print("__init__方法被呼叫")

    def run(self, speed):
        print(self.color, '', self.brand, self.model, '正在以', speed, '公里/小時的速度行駛')

    def change_color(self, c):
        self.color = c


a4 = Car('紅色', '奧迪', 'A4')
a4.run(199)
a4.change_color("白色")
a4.run(280)
x5 = Car('藍色', '寶馬', 'x5')
x5.run(188)
示例:

3.析構方法 __del__

        析構方法概述:
            1.在物件被銷毀之前被呼叫,主要負責清理物件所占用的資源
            2.Python建議盡可能少的在析構方法內做事情,因為銷毀時間難以確定
            3.物件借用了作業系統的資源還要通過析構方法歸還資源,如檔案資源,網路資源
            4.語法形式:
                class 類名:
                    def __del__(self):
                        陳述句塊

class FileManage:
    """定義一個檔案管理員類"""
    def __init__(self, filename='a.txt'):
        self.file = open(filename, 'w')

    def writeline(self, string):
        self.file.write(string)
        self.file.write('\n')

    def __del__(self):
        """析構方法會在物件銷毀前自動呼叫"""
        self.file.close()
        print("檔案已關閉")


fm = FileManage()
fm.writeline("hello world")
fm.writeline("這是中文寫的第二行")
del fm  # 檔案已關閉
# 死回圈永遠不退出,del不呼叫一直不關閉檔案
while True:
    pass
print("程式結束")
示例:

4.呼叫方法 __call__

        在創建型別的時候定義了__call__方法,這個物件就類似函式一樣是可呼叫的,相當于 物件()
        在寫類的裝飾器時會用到__call__方法

class A:
    def __call__(self, *args, **kwargs):
        print('執行call方法了')
    def call(self):
        print('執行call方法了')


class B:
    def __init__(self, cls):
        print('在實體化A之前做一些事情')
        self.a = cls()
        self.a()
        print('在實體化A之后做一些事情')


a = A()
# 物件() 相當于呼叫__call__方法
a()  # 執行call方法了
a.call()  # 執行call方法了

# 類名()()相當于先實體化得到一個物件,再對物件(),和上面的結果一樣,相當于呼叫__call__方法
A()()  # 執行call方法了
B(A)
"""B(A)執行結果
    在實體化A之前做一些事情
    執行call方法了
    在實體化A之后做一些事情
    Out[11]: <__main__.B at 0x550a9b0>  # 這行是呼叫B類的基類object的__call__方法執行的結果
"""
示例:

5.item系列方法(__getitem__, __setitem__, __delitem__)

        item方法概述:
            1.item系列方法和物件使用[]訪問值有聯系,用于索引切片操作,常用語字典和串列物件
            2.Python3中的切片方法不再是Python2中的__getslice__(), __setslice__()和__delslice__()
            3.Python3中借助slice類把分片整合到了__getitem__(),__setitem__()和 __delitem__()中

obj = {'k':'v'}
# 字典的物件
print(obj)  #  {'k': 'v'}
print(obj['k'])  # v

class B:
    def __getitem__(self, item):
        return getattr(self, item)
        
    def __setitem__(self, key, value):
        setattr(self, key, value*2)
        
    def __delitem__(self, key):
        delattr(self, key)
        
        
b = B()
# b.k2 = 'v2'
# print(b.k2)

# __setitem__
b['k1'] = 'v1'
# __getitem__
print(b['k1'])  # v1v1
# __delitem__
del b['k1']
# print(b['k1'])  # 會報錯
示例1:
# 字典的物件
class Foo:
    def __init__(self, name):
        self.name = name

    def __getitem__(self, item):
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        self.__dict__[key] = value
        
    def __delitem__(self, key):
        print('del obj[key]時,我執行')
        self.__dict__.pop(key)

    def __delattr__(self, item):
        print('del obj.key時,我執行')
        self.__dict__.pop(item)


f1 = Foo('sb')
f1['age'] = 18
f1['age1'] = 19
del f1.age1  # del obj.key時執行
del f1['age']  # del obj[key]時執行
f1['name'] = 'coco'
print(f1.__dict__)  # {'name': 'coco'}
示例2:
# 字典的物件
class Foo():
    def __getattr__(self, item):
        print("執行了getattr查找%s" % item)

    # 無論是否找到屬性都會執行getattribute
    def __getattribute__(self, item):
        print("執行了getattribute查找%s" % item)
        raise AttributeError("拋出例外")


f1 = Foo()
# isinstance(obj, cls)判斷物件obj是否是類cls實體化出來的物件
print(isinstance(f1, Foo))  # True
f1.x
"""f1.x執行結果
    執行了 __getattribute__ 查找x
    執行了 __getattr__ 查找x
"""


class Bar():
    # 只針對字典方式操作觸發
    def __getitem__(self, item):
        print("%s getitem" % item)
        return self.__dict__[item]

    # 只針對字典方式操作觸發
    def __setitem__(self, key, value):
        print("%s:%s setitem" % (key, value))
        self.__dict__[key] = value

    # 只針對字典方式操作觸發
    def __delitem__(self, key):
        print("%s delitem" % key)
        self.__dict__.pop(key)


# issubclass(sub, super)判斷子類sub是否是由父類super繼承來的派生類 
print(issubclass(Bar, Foo))  # False
f2 = Bar()
f2["name"] = "coco"  # name:coco setitem
print(f2["name"])
"""print(f2["name"])執行結果
    name getitem
    coco
"""
f2["age"] = "18"  # age:18 setitem
print(f2.__dict__)  # {'name': 'coco', 'age': '18'}
del f2["age"]  # age delitem
print(f2.__dict__)  # {'name': 'coco'}
示例3:
# 串列的物件
class Foo(object):
    def __getitem__(self, index):
        if isinstance(index, slice):
            print("Get slice---------> start: %s, stop: %s, step: %s." \
                    % (str(index.start), str(index.stop), str(index.step)))

    def __setitem__(self, index, value):
        if isinstance(index, slice):
            print("Set slice---------> start: %s, stop: %s, step: %s." \
                    % (str(index.start), str(index.stop), str(index.step)))
            print("\tThe value is:", value)
        
    def __delitem__(self, index):
        if isinstance(index, slice):
            print("Delete slice------> start: %s, stop: %s, step: %s." \
                    % (str(index.start), str(index.stop), str(index.step)))


if __name__ == "__main__":
    obj = Foo()
    obj[-1:10]  # Get slice---------> start: -1, stop: 10, step: None.
    obj[-1:10:1] = [2, 3, 4, 5]
    """obj[-1:10:1] = [2, 3, 4, 5]執行結果
        Set slice---------> start: -1, stop: 10, step: 1.
            The value is: [2, 3, 4, 5]
    """
    del obj[-1:10:2]  # Delete slice------> start: -1, stop: 10, step: 2.
示例4:
# Python2中的分片(切片)操作 __getslice__ __setslice__ __delslice__
class Foo(object):
    def __getslice__(self, i, j):
        print('__getslice__', i, j)

    def __setslice__(self, i, j, sequence):
        print('__setslice__', i, j)

    def __delslice__(self, i, j):
        print('__delslice__', i, j)
        


obj = Foo()
obj[-1:1]  # 自動觸發執行 __getslice__
obj[0:1] = [11, 22, 33, 44]  # 自動觸發執行 __setslice__
del obj[0:2]  # 自動觸發執行 __delslice__
示例5:

6.__eq__ 方法

        __eq__方法定義了類的等號(==)行為

class A:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __eq__(self, other):
        if self.name == other.name and self.age == other.age:
            return True
            
            
a = A('gogo', 83)
aa = A('gogo', 83)
aa2 = A('gogo', 83)
aa3 = A('gogo', 83)
aa4 = A('gogo', 83)
print(a, aa)
# <__main__.A object at 0x0000000004F94FD0> <__main__.A object at 0x0000000004F94748>
# ==這個語法 是完全和__eq__ 相同
print(aa3 == aa == aa4)  # True
示例:

7.__str__ 方法和 __repr__ 方法

        str函式和repr函式概述:
            str函式回傳物件的描述資訊print函式輸出使用
            str函式或者print函式 實際呼叫--->obj.__str__(), print("%s", 變數名)
            repr函式回傳一個能代表次物件的字串運算式(這個字串是給Python解釋器識別用的),通常用于遠程通信資料校驗
            repr函式用于遠程通信資料校驗示例:eval(repr(obj)) == obj
            repr函式或者互動式解釋器 實際呼叫--->obj.__repr__(), print("%r", 變數名)
        __str__ 和 __repr__ 方法概述:
            如果__str__沒有被定義,那么原本呼叫__str__方法的語法就會使用__repr__來代替輸出
            __str__ 和 __repr__ 方法的回傳值必須是字串,否則拋出例外
        查找順序:
            1.在子類中使用__str__,先找子類的__str__,沒有的話要向上找,只要父類不是object,就執行父類的__str__
            2.但是如果除了object之外的父類都沒有__str__方法,就執行子類的__repr__方法
            3.如果子類沒有__repr__方法,還要向上找父類中的__repr__方法,一直找不到再執行object類中的__str__方法

class Foo1():
    # 運用在print列印時觸發
    def __str__(self):
        return "自定義列印資訊"

    # 運用在解釋器時觸發
    def __repr__(self):
        return "自定義列印資訊2"


obj = Foo1()
print(obj)  # 自定義列印資訊
# __str__和 __repr__共存,print先找str沒有再找repr
print(obj)  # 自定義列印資訊
示例1:
class B:
     def __str__(self):
         return 'str : class B'

     def __repr__(self):
         return 'repr : class B'


b=B()
print('%s' % b)
print('%r' % b)
示例2:

8.格式化字串方法 __format__

# __format__ 格式化方法示例
format_dic = {
    "ymd": "{0.year}{0.mon}{0.day}",
    "m-d-y": "{0.mon}-{0.day}-{0.year}",
}

class Date:
    def __init__(self, year, mon, day):
        self.year = year
        self.mon = mon
        self.day = day

    def __format__(self, format_spec):
        print("-->", format_spec)
        if not format_spec or format_spec not in format_dic:
            format_spec = "ymd"
        fm = format_dic[format_spec]
        return fm.format(self)


d1 = Date(2019, 4, 13)
print("{0.year}{0.mon}{0.day}".format(d1))  # 2019413

print(format(d1, "ymd"))  # 2019413
print(format(d1, "m-d-y"))  # 4-13-2019
示例:

9.描述符方法(__get__, __set__, __delete__)

        1.描述符概述(描述符協議):
            描述符本質就是一個新式類,在這個新式類中,至少實作了__get__(),__set__(),__delete__()中的一個
            __get__(): 呼叫一個屬性時,觸發
            __set__(): 為一個屬性賦值時,觸發
            __delete__(): 使用del洗掉屬性時,觸發
            資料描述符: 至少實作了__get__()和__set__()
            非資料描述符: 沒有實作: __set__()

        2.描述符應用示例

class Foo4():
    def __get__(self, instance, owner):
        print("get")

    def __set__(self, instance, value):
        print("set")

    def __delete__(self, instance):
        print("delete")


class Foo5(Foo4):
    name = Foo4()


f5 = Foo5()
f5.name  # get
f5.name = 1 # set
del f5.name  # delete
示例1:
class Typed:
    def __init__(self, key, expected_type):
        self.key = key
        self.expected_type = expected_type
        
    def __get__(self, instance, owner):
        print('get方法')
        # print('instance引數【%s】' %instance)
        # print('owner引數【%s】' %owner)
        return instance.__dict__[self.key]
        
    def __set__(self, instance, value):
        print('set方法')
        # print('instance引數【%s】' % instance)
        # print('value引數【%s】' % value)
        # print('====>',self)
        if not isinstance(value,self.expected_type):
            # print('你傳入的型別不是字串,錯誤')
            # return
            raise TypeError('%s 傳入的型別不是%s' %(self.key, self.expected_type))
        instance.__dict__[self.key] = value
        
    def __delete__(self, instance):
        print('delete方法')
        # print('instance引數【%s】' % instance)
        instance.__dict__.pop(self.key)


class People:
    name = Typed('name', str)  # t1.__set__()  self.__set__()
    age = Typed('age', int)  # t1.__set__()  self.__set__()
    def __init__(self, name, age, salary):
        self.name = name
        self.age = age
        self.salary = salary


p1 = People("coco", 13, 13.3)
print(p1.__dict__)  # {'name': 'coco', 'age': 13, 'salary': 13.3}
示例2:

        3.描述符的優先級
            類屬性 > 資料描述符 > 實體屬性 > 非資料描述符 > 找不到的屬性觸發__getattr__()

            1.類屬性 > 資料描述符

#描述符Str
class Str:
    def __get__(self, instance, owner):
        print('Str呼叫')

    def __set__(self, instance, value):
        print('Str設定...')

    def __delete__(self, instance):
        print('Str洗掉...')

class People:
    name = Str()
    def __init__(self, name, age):  # name被Str類代理,age被Int類代理
        self.name = name
        self.age = age


# 在一個類中定義描述符它就是一個類屬性,存在于類的屬性字典中,而不是實體的屬性字典
# 描述符被定義成了一個類屬性,直接通過類名也可以呼叫類屬性name,本質就是在呼叫描述符Str,觸發了__get__()
People.name  # Str呼叫

# 賦值并沒有觸發__set__()
People.name = 'coco'
# del也沒有觸發__delete__()
del People.name
'''原因: 描述符在使用時被定義成另外一個類的類屬性,因而類屬性比二次加工的描述符偽裝而來的類屬性有更高的優先級
    People.name  # 呼叫類屬性name,找不到就去找描述符偽裝的類屬性name,觸發了__get__()
    People.name = 'coco'  # 直接賦值了一個類屬性,它擁有更高的優先級,相當于覆寫了描述符不會觸發描述符的__set__()
    del People.name  # 直接洗掉一個類屬性,它擁有更高的優先級,相當于覆寫了描述符不會觸發描述符的__delete__()
'''
示例:

            2.資料描述符 > 實體屬性

#描述符Str
class Str:
    def __get__(self, instance, owner):
        print('Str呼叫')

    def __set__(self, instance, value):
        print('Str設定...')

    def __delete__(self, instance):
        print('Str洗掉...')


class People:
    name=Str()
    def __init__(self, name, age):  # name被Str類代理,age被Int類代理
        self.name = name
        self.age = age


p1 = People('angels', 18)  # Str設定...

# 如果描述符是一個資料描述符(即有__get__又有__set__)
# 那么p1.name的呼叫與賦值都是觸發描述符的操作,與p1本身無關了相當于覆寫了實體的屬性
p1.name ='coco'  # # Str設定...
p1.name  # Str呼叫
# 實體的屬性字典中沒有name,因為name是一個資料描述符,優先級高于實體屬性
# 查看/賦值/洗掉都是跟描述符有關,與實體無關
print(p1.__dict__)  # {'age': 18}
del p1.name  # Str洗掉...
示例:

            3.實體屬性 > 非資料描述符

class Foo:
    def __set__(self, instance, value):
        print('set')

    def __get__(self, instance, owner):
        print('get')


class Room:
    name = Foo()
    def __init__(self, name, width, length):
        self.name = name
        self.width = width
        self.length = length


# name是一個資料描述符,因為name = Foo()而Foo實作了get和set方法,因而比實體屬性有更高的優先級
# 對實體的屬性操作,觸發的都是描述符的方法
r1 = Room('廁所', 1, 1)  # set
r1.name  # get
r1.name = '廚房'  # set



class Foo:
    def __get__(self, instance, owner):
        print('get')


class Room:
    name = Foo()
    def __init__(self, name, width, length):
        self.name = name
        self.width = width
        self.length = length


# name是一個非資料描述符,因為name=Foo()而Foo沒有實作set方法,因而比實體屬性有更低的優先級
# 對實體的屬性操作,觸發的都是實體自己的方法
r1 = Room('廁所', 1, 1)
r1.name
r1.name = '廚房'
示例:

            4.非資料描述符 > 找不到

class Foo:
    def func(self):
        print('func被呼叫')

    def __getattr__(self, item):
        print('找不到就呼叫getattr', item)


f1=Foo()
f1.xxx  # 找不到就呼叫getattr xxx
示例:

        4.用描述符定制 靜態屬性@property, 類方法@classmethod, 靜態方法@staticmethod

            1.定制靜態屬性@property

class Lazyproperty:
    def __init__(self, func):
        print('==========>', func)
        self.func = func
        
    def __get__(self, instance, owner):
        print('get')
        # print(instance)
        # print(owner)
        if instance is None:
            return self
        res = self.func(instance)
        setattr(instance, self.func.__name__, res)
        return res


class Room:
    def __init__(self, name, width, length):
        self.name = name
        self.width = width
        self.length = length
        
    # @property #area = property(area)
    @Lazyproperty  #area = Lazypropery(area)
    def area(self):
        return self.width * self.length
        
    @property  #test = property(test)
    def area1(self):
        return  self.width * self.length


r1 = Room("coco", 10, 10)  # ======> <function Room.area at 0x0000000006AC4C80>

print(r1.area1)  # 100
# 先從自己的屬性字典找,沒有再去類的中找,然后觸發了area的__get__方法
print(r1.area)  # 先列印get, 再列印100
# 先從自己的屬性字典找,找到了,是上次計算的結果,這樣就不用每執行一次都去計算
print(r1.area)  # 先列印100, 再列印get
print(Room.area)  # <__main__.Lazyproperty object at 0x0000000005AE52B0>
print(Room.area1)  # <property object at 0x00000000052F1458>
示例:

            2.定制類方法@classmethod

class ClassMethod:
    def __init__(self, func):
        self.func = func

    # 類來呼叫,instance為None,owner為類本身,實體來呼叫,instance為實體,owner為類本身
    def __get__(self, instance, owner):
        def feedback():
            print('在這里可以加功能啊...')
            return self.func(owner)
        return feedback


class People:
    name = 'coco'
    @ClassMethod  # say_hi = ClassMethod(say_hi)
    def say_hi(cls):
        print('你好啊,world %s' % cls.name)


People.say_hi()

p1 = People()
p1.say_hi()


class ClassMethod:
    def __init__(self, func):
        self.func = func

    # 類來呼叫,instance為None,owner為類本身,實體來呼叫,instance為實體,owner為類本身
    def __get__(self, instance, owner):
        def feedback(*args, **kwargs):
            print('在這里可以加功能啊...')
            return self.func(owner, *args, **kwargs)
        return feedback


class People:
    name = 'linhaifeng'
    @ClassMethod # say_hi = ClassMethod(say_hi)
    def say_hi(cls, msg):
        print('你好啊,world %s %s' %(cls.name, msg))


People.say_hi('每天都是充滿希望的一天')

p1 = People()
p1.say_hi('每天都是充滿希望的一天')
示例:

            3.定制靜態方法@staticmethod

class StaticMethod:
    def __init__(self, func):
        self.func = func

    # 類來呼叫,instance為None,owner為類本身,實體來呼叫,instance為實體,owner為類本身
    def __get__(self, instance, owner):
        def feedback(*args, **kwargs):
            print('在這里可以加功能啊...')
            return self.func(*args, **kwargs)
        return feedback


class People:
    @StaticMethod  # say_hi = StaticMethod(say_hi)
    def say_hi(x, y, z):
        print('------>', x, y, z)


People.say_hi(1, 2, 3)

p1 = People()
p1.say_hi(4, 5, 6)
示例:

10.背景關系管理器方法(__enter__, __exit__)

        背景關系管理器內部必須實作 __enter__ __exit__ 方法

class Open():
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print("執行了enter")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("執行了exit")
        print(exc_type)  # 例外型別
        print(exc_val)  # 例外值
        print(exc_tb)  # 例外追蹤資訊


with Open("a.txt") as f:
    print(f)  # <__main__.Foo6 object at 0x000000000358E0F0>
    print(f.name)  # a.txt
print("結束")  # 結束
示例1:
class A:
    def __enter__(self):
        print('before')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('after')


with A() as a:
    print('123')
示例2:
class A:
    def __init__(self):
        print('init')
        
    def __enter__(self):
        print('before')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('after')


with A() as a:
    print('123')
示例3:
class Myfile:
    def __init__(self, path, mode='r', encoding='utf-8'):
        self.path = path
        self.mode = mode
        self.encoding = encoding

    def __enter__(self):
        self.f = open(self.path, mode=self.mode, encoding=self.encoding)
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.f.close()


with Myfile('file',mode='w') as f:
    f.write('wahaha')
示例4:
import  pickle


class MyPickledump:
    def __init__(self, path):
        self.path = path

    def __enter__(self):
        self.f = open(self.path, mode='ab')
        return self

    def dump(self, content):
        pickle.dump(content, self.f)

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.f.close()


class Mypickleload:
    def __init__(self, path):
        self.path = path

    def __enter__(self):
        self.f = open(self.path, mode='rb')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.f.close()

    def load(self):
         return pickle.load(self.f)

    def loaditer(self):
        while True:
            try:
                yield self.load()
            except EOFError:
                break



# with MyPickledump('file') as f:
#      f.dump({1, 2, 3, 4})
with Mypickleload('file') as f:
    for item in f.loaditer():
        print(item)
示例5:
import  pickle
class MyPickledump:
    def __init__(self, path):
        self.path = path

    def __enter__(self):
        self.f = open(self.path, mode='ab')
        return self

    def dump(self, content):
        pickle.dump(content, self.f)

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.f.close()


class Mypickleload:
    def __init__(self, path):
        self.path = path

    def __enter__(self):
        self.f = open(self.path, mode='rb')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.f.close()

    def __iter__(self):
        while True:
            try:
                yield  pickle.load(self.f)
            except EOFError:
                break



# with MyPickledump('file') as f:
#      f.dump({1, 2, 3, 4})
with Mypickleload('file') as f:
    for item in f:
        print(item)
示例6:

11.哈希方法 __hash__

        哈希方法概述:
            1.Python底層資料結構是基于hash值尋址的優化操作
            2.hash是一個演算法能夠把某一個要存在記憶體里的值通過一系列計算,保證不同值的hash結果是不一樣的

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __hash__(self):
        return hash(str(self.a) + str(self.b))


a = A()
print(hash(a))  # -7282248652925619321
hash("12")  # -7282248652925619321
示例:

12.__len__ 方法

        __len__ 方法用于獲取一個物件的元素個數

class B:
    def __len__(self):
        print("len函式觸發__len__方法")
        return 0


b = B()
# len一個物件就會觸發 __len__方法
len(b)
"""len(b)執行結果
    len函式觸發__len__方法
    0
"""
示例1:
class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __len__(self):
        print(self.__dict__)  # {'a': 1, 'b': 2}
        return len(self.__dict__)  # 2


a = A()
print(len(a))  # 2
示例2:

13.實作迭代器協議的 __next__ 和 __iter__ 方法

        方法概述:
            __iter__ 方法用于迭代器,串列字典元組可以進行for回圈,也是因為型別內部定義了__iter__ 方法
            __next__ 方法訪問可迭代物件的資料,如果沒有資料則觸發 StopIteration 例外來通知呼叫者停止迭代即迭代器協議

class Foo(object):
    def __init__(self, sq):
        self.sq = sq

    def __iter__(self):
        return iter(self.sq)


obj = Foo([11, 22, 33, 44])
for i in obj:
    print(i, end=" ")  # 11 22 33 44
示例1:
# 模擬range函式加上步長
class Range:
    def __init__(self, start, stop, step):
        self.start = start
        self.stop = stop
        self.step = step

    def __next__(self):
        if self.start >= self.stop:
            raise StopIteration
        x = self.start
        self.start += self.step
        return x

    def __iter__(self):
        return self


for i in Range(1, 7, 3):
    print(i)
示例2:
# 斐波拉契數列
class Fib:
    def __init__(self):
        self._a = 0
        self._b = 1

    def __iter__(self):
        return self

    def __next__(self):
        self._a, self._b = self._b, self._a + self._b
        return self._a


f1=Fib()
print(f1.__next__())
print(next(f1))
print(next(f1))

for i in f1:
    if i > 100:
        break
    print('%s ' % i, end=' ')
示例3:

14.__getattribute__ 方法

        方法概述:
            1.當 __getattribute__ 與 __getattr__ 同時存在,只會執行 __getattribute__
            2.當 __getattribute__ 在執行程序中拋出例外 AttributeError 時才會同時執行 __getattr__

class Foo:
    def __init__(self, name):
        self.name = name

    def __getattr__(self, item):
        print('__getattr__執行')
        # return self.__dict__[item]

    def __getattribute__(self, item):
        print('無論如何都會執行')
        raise AttributeError('發生了例外')


f1 = Foo("Coco")
f1.x
f1.xx
示例:

14.單例的實作

    單例概述: 單例類從頭到尾只能有一個實體且從頭到尾之開辟了一塊兒屬于物件的空間

class Single:
    __ISINCTANCE = None
    def __new__(cls, *args, **kwargs):
        if not cls.__ISINCTANCE:
            cls.__ISINCTANCE = object.__new__(cls)
        return cls.__ISINCTANCE
        
    def __init__(self, name, age):
        # self.name = name
        # self.age = age
        print(self)


s1 = Single('coco', 23)  # <__main__.Single object at 0x10f67fad0>
s2 = Single('gogo', 40)  # <__main__.Single object at 0x10f67fad0>
示例1:
class MusicPlayer(object):

    # 記錄第一個被創建物件的參考
    instance = None

    # 記錄是否執行過初始化動作
    init_flag = False

    def __new__(cls, *args, **kwargs):

        # 1.判斷類屬性是否是空物件
        if cls.instance is None:
            # 2.呼叫父類方法,為第一個物件分配空間
            cls.instance = super().__new__(cls)

        # 3.回傳類屬性保存的物件參考
        return cls.instance

    def __init__(self):

        # 1.判斷是否執行過初始化動作
        if MusicPlayer.init_flag:
            return
        # 2.沒有執行過,再執行初始化動作
        print("初始化播放器")
        # 3.修改類屬性標記
        MusicPlayer.init_flag = True  


player1 = MusicPlayer()  # 初始化播放器
print(player1)  # <__main__.MusicPlayer object at 0x0000000006AA28D0>
player2 = MusicPlayer()
print(player2)  # <__main__.MusicPlayer object at 0x0000000006AA28D0>
示例2:

15.函式模擬面向物件設計與類的面向物件設計對比

    1.函式模擬面向物件設計

def dogs(name, gender, type):
    # 狗的屬性
    def init(name, gender, type):
        dog = {
            "name": name,
            "gender": gender,
            "type": type,
            "run": run
        }
        return dog

    # 狗的方法
    def run(dog):
        print("一條狗%s正在跑" % dog["name"])

    return init(name, gender, type)


d1 = dogs("wangcai", "", "中華田園犬")
d2 = dogs("xiaoqiang", "", "哈士奇")
print("面向物件設計", d1)
d1["run"](d1)
print(d2["name"])
示例:

    2.類實作面向物件設計

# 面向物件編程-->用面向物件獨有的class語法實作面向物件設計
class Dog:
    """定義一個狗類"""
    def __init__(self,name, gender, type):
        self.name = name
        self.gender = gender
        self.type = type

    def run(self):
        print("一條狗%s正在跑" % self.name)


dog1 = Dog("wangcai", "", "中華田園犬")
dog2 = Dog("xiaoqiang", "", "哈士奇")

print("面向物件編程", dog1.__dict__)  # __dict__ 查看屬性字典
print(dog1.__dict__["type"])  # 中華田園犬

# 創建出的實體只有資料屬性,函式屬性實際是調的類的函式屬性
dog1.run()
print(dog2.name)

# 查看類的名字
print(Dog.__name__)  # Dog
# 查看檔案說明
print(Dog.__doc__)  # 定義一個狗類
# 查看第一個父類
print(Dog.__base__)  # <class 'object'>
# 查看所有父類,構成元組
print(Dog.__bases__)  # (<class 'object'>,)
# 查看類的屬性,回傳一個字典
print(Dog.__dict__)
# 查看類定義所在的模塊
print(Dog.__module__)  # __main__
# 查看實體對應的類
print(Dog.__class__)  # <class 'type'>
示例:

16.組合

    組合概述: 給一個類的物件封裝一個屬性,這個屬性是另一個類的物件

class GameRole:
    """英雄人物類"""
    def __init__(self, name, ad, hp):
        self.name = name
        self.ad = ad
        self.hp = hp

    def attack(self,p):
        p.hp = p.hp - self.ad
        print('%s 攻擊 %s,%s 掉了%s血,還剩%s血' %(self.name, p.name, p.name, self.ad, p.hp))

    def armament_weapon(self, wea):
        self.wea = wea


class Weapon:
    """武器屬性類"""
    def __init__(self, name, ad):
        self.name = name
        self.ad = ad

    def fight(self, p1, p2):
        p2.hp = p2.hp - self.ad
        print('%s 用%s打了%s\t%s 掉了%s血,還剩%s血'\
              % (p1.name, self.name, p2.name, p2.name, self.ad, p2.hp))


p1 = GameRole('coco', 20, 500)
p2 = GameRole('cat', 50, 200)
axe = Weapon('三板斧', 60)
broadsword = Weapon('屠龍寶刀', 100)
p1.armament_weapon(axe)  # 給coco裝備了三板斧這個物件.
p1.wea.fight(p1, p2)  # coco 用三板斧打了cat    cat 掉了60血,還剩140血
示例1:
# 組合實作與類的關聯
class School:
    def __init__(self, name, addr):
        self.name = name
        self.addr = addr


class Course:
    def __init__(self, name, price, school):
        self.name = name
        self.price = price
        self.school = school


s1 = School("coco", "成都")
s2 = School("coco", "廣州")
msg = """
1 coco 成都
2 coco 廣州
"""

while True:
    print(msg)
    menu = {
        "1": s1,
        "2": s2
    }
    choice = input("請選擇學校>>>:")
    school_obj = menu[choice]

    name = input("課程名: ")
    price = input("課程費用: ")

    new_course = Course(name, price, school_obj)
    print("課程 %s 屬于 %s 學校" % (new_course.name, new_course.school.name))
示例2:

17.封裝 enclosure

    封裝概述:
        1.封裝是指隱藏類的實作細節讓使用者不關心這些細節,目的是讓使用者通過盡可能少的使用實體屬性操作物件
        2.私有成員有兩種: 私有屬性和私有方法,python類中以雙下劃線('__')開頭且不以雙下劃線結尾的識別符號為私有成員
        3.私有成員只能被方法呼叫,不能在子類或其它地方使用
        4.廣義的封裝: 把屬性和方法封裝在類中,定義一個規范來描述一類事物
        5.狹義的封裝: 私有化,只能在類的內部訪問

class A:
    def __init__(self):
        self.__p1 = 100  # 創建私有屬性
        
    def __m1(self):
        print("A類的私有方法被呼叫!")
        
    def test(self):
        print(self.__p1)  # 可以訪問
        self.__m1()  # 可以訪問
        
        
a = A()
# print(a.__p1)  # 出錯,不可以訪問
# a.__m1()  # 出錯, 在類外部不能呼叫類的私有方法
a.test()  # 用方法來操作私有屬性和私有方法
a.__dict__  # {'_A__p1': 100}
a._A__p1  # 100
a._A__m1()  # A類的私有方法被呼叫!
示例1:
class Parent:
    def __func(self):
        print('in Parent func')

    def __init__(self):
        self.__func()


class Son(Parent):
    def __func(self):
        print('in Son func')


son1 = Son()  # in Parent func
示例2:

18.繼承 inheritance 和派生 derived

    1.繼承和派生概述:
        1.繼承是從已有類中派生出新類,新類具有原類的資料屬性和行為,并能擴展新的能力
        2.派生就是從一個已有的類衍生出新類,在新的類上添加新的屬性和行為
        3.任何類都直接或間接的繼承自object類,object類是一切類的超類
        4.用繼承派生機制,可以將一些共有功能加在基類中實作代碼的共享,在不改變超類的代碼的基礎上改變原有的功能
        5.繼承和派生流程圖: https://www.processon.com/view/link/5ee0d5cc07912929cb38f831
        6.術語名詞: 基類(base class) 超類(super class) 父類(father class) 派生類(derived class) 子類(child class)

    2.單繼承:

        語法:
            class 類名(超類名):
                陳述句塊

class Human:  #
    def say(self, what):  # 說話的行為
        print("說: ", what)
    def walk(self, distance):  # 走路的行為
        print("走了", distance, "公里")


h1 = Human()
h1.say("今天天氣不錯!")
h1.walk(5)


class Student(Human):
    # def say(self, what):  # 說話的行為
    #     print("說: ", what)

    # def walk(self, distance):  # 走路的行為
    #     print("走了", distance, "公里")

    def study(self, subject):
        print("正在學習", subject)


s1 = Student()
s1.say("今天晚飯吃什么?")
s1.walk(3)
s1.study("python")
示例:

    3.多繼承 multiple inheritance
        多繼承概述:
            1.多繼承是指一個子類繼承自兩個或兩個以上的基類
            2.多繼承的問題(缺陷): 識別符號(名字空間)沖突的問題,要謹慎使用多繼承
        語法:
            class 類名(超類名1, 超類名2, ...):
                pass

class Car:
    def run(self, speed):
        print("汽車以", speed, "km/h的速度行駛")


class Plane:
    def fly(self, height):
        print("飛機以海拔", height, "米的高度飛行")


class PlaneCar(Car, Plane):
    """飛行汽車類, 同時繼承 自Car和 Plane"""
    pass


p1 = PlaneCar()
p1.fly(10000)  # 飛機以海拔 10000 米的高度飛行
p1.run(299)  # 汽車以 299 km/h的速度行駛
示例1:
# 多繼承缺陷示例
# 小張寫了一個類A
class A:
    def m(self):
        print("A.m()被呼叫")
        
        
# 小李寫了一個類B:
class B:
    def m(self):
        print("B.m() 被呼叫")
        
        
# 小王感覺小張和小李寫的兩個類自己可以用
class AB(A, B):
    pass
    
    
ab = AB()
ab.m()  # 呼叫A類中的m方法
示例2:

    4.多繼承的 MRO (Method Resolution Order)問題
        MRO 方法搜索順序問題
            子類繼承父類時MRO查找順序為C3演算法
            MRO順序-廣度優先和深度優先流程圖: https://www.processon.com/view/link/5ee103c907912929cb39509a
            python 3 廣度優先: 一條路走到倒數第二級,判斷如果其他路能走到終點,則回傳走另一條路,如果不能則走到終點
            python 2 深度優先: 一條路走到底

class E:
    pass


class F:
    pass


class A(E):
    pass


class B(E):
    pass


class C(F):
    pass


class D(F):
    pass


class AB(A, B):
    pass


class CD(C, D):
    pass


class ABCD(AB, CD):
    pass


print(ABCD.__mro__)
"""Python3運行結果
    (__main__.ABCD,
     __main__.AB,
     __main__.A,
     __main__.B,
     __main__.E,
     __main__.CD,
     __main__.C,
     __main__.D,
     __main__.F,
     object)
"""
示例:

    5.子類呼叫父類方法

print("******多繼承使用類名.__init__ 發生的狀態******")
class Parent(object):
    def __init__(self, name):
        print('parent的init開始被呼叫')
        self.name = name
        print('parent的init結束被呼叫')


class Son1(Parent):
    def __init__(self, name, age):
        print('Son1的init開始被呼叫')
        self.age = age
        Parent.__init__(self, name)
        print('Son1的init結束被呼叫')


class Son2(Parent):
    def __init__(self, name, gender):
        print('Son2的init開始被呼叫')
        self.gender = gender
        Parent.__init__(self, name)
        print('Son2的init結束被呼叫')


class Grandson(Son1, Son2):
    def __init__(self, name, age, gender):
        print('Grandson的init開始被呼叫')
        Son1.__init__(self, name, age)  # 單獨呼叫父類的初始化方法
        Son2.__init__(self, name, gender)
        print('Grandson的init結束被呼叫')


gs = Grandson('grandson', 12, '')
print('姓名: ', gs.name)
print('年齡: ', gs.age)
print('性別: ', gs.gender)

print("******多繼承使用類名.__init__ 發生的狀態******\n\n")
單獨呼叫父類的方法示例:
print("******單繼承使用super().__init__ 發生的狀態******")
class Parent(object):
    def __init__(self, name):
        print('parent的init開始被呼叫')
        self.name = name
        print('parent的init結束被呼叫')


class Son1(Parent):
    def __init__(self, name, age):
        print('Son1的init開始被呼叫')
        self.age = age
        super().__init__(name)  # 單繼承不能提供全部引數
        print('Son1的init結束被呼叫')


class Grandson(Son1):
    def __init__(self, name, age, gender):
        print('Grandson的init開始被呼叫')
        super().__init__(name, age)  # 單繼承不能提供全部引數
        print('Grandson的init結束被呼叫')


gs = Grandson('grandson', 12, '')
print('姓名: ', gs.name)
print('年齡: ', gs.age)
#print('性別: ', gs.gender)
print("******單繼承使用super().__init__ 發生的狀態******\n\n")
單繼承中super呼叫父類方法示例:
print("******多繼承使用super().__init__ 發生的狀態******")
class Parent(object):
    def __init__(self, name, *args, **kwargs):  # 為避免多繼承報錯,使用不定長引數,接受引數
        print('parent的init開始被呼叫')
        self.name = name
        print('parent的init結束被呼叫')


class Son1(Parent):
    # 為避免多繼承報錯,使用不定長引數,接受引數
    def __init__(self, name, age, *args, **kwargs):
        print('Son1的init開始被呼叫')
        self.age = age
        super().__init__(name, *args, **kwargs)  # 為避免多繼承報錯,使用不定長引數,接受引數
        print('Son1的init結束被呼叫')


class Son2(Parent):
    # 為避免多繼承報錯,使用不定長引數,接受引數
    def __init__(self, name, gender, *args, **kwargs):
        print('Son2的init開始被呼叫')
        self.gender = gender
        super().__init__(name, *args, **kwargs)  # 為避免多繼承報錯,使用不定長引數,接受引數
        print('Son2的init結束被呼叫')


class Grandson(Son1, Son2):
    def __init__(self, name, age, gender):
        print('Grandson的init開始被呼叫')
        # 多繼承時,相對于使用類名.__init__方法,要把每個父類全部寫一遍
        # 而super只用一句話,執行了全部父類的方法,這也是為何多繼承需要全部傳參的一個原因
        # super(Grandson, self).__init__(name, age, gender)
        super().__init__(name, age, gender)
        print('Grandson的init結束被呼叫')


print(Grandson.__mro__)

gs = Grandson('grandson', 12, '')
print('姓名: ', gs.name)
print('年齡: ', gs.age)
print('性別: ', gs.gender)
print("******多繼承使用super().__init__ 發生的狀態******\n\n")
多繼承中super呼叫有所父類的被重寫的方法示例:

19.多型 polymorphic

    多型概述:
        1.多型是指在有繼承/派生關系的類中,呼叫基類物件的方法,實際能呼叫子類的覆寫方法的現象叫多型
        2.多型是不同的子類物件呼叫相同的父類方法產生不同的執行結果,即多型要以繼承和重寫父類方法為前提
        3.多型是一種型別的多種形態,多個子類去繼承父類,那么每一個子類都是父類的一種形態
        4.Python的全部物件只有"運行時狀態(動態)"沒有"C++/Java"里的"編譯時狀態(靜態)"
        5.Python中沒有多型但處處是多型,因為Python中所有的類都繼承自object基類
        6.Python要實作靜態就只能在防范命名時不要覆寫基類的方法

class Shape:
    def draw(self):
        pass

class Point(Shape):
    def draw(self):
        print("正在畫一個點")

class Circle(Point):
    def draw(self):
        print("正在畫一個圓")


def my_draw(s):
    s.draw()  # 根據實體的型別在運行時動態決定呼叫的方法,這樣的行為為動態


s1 = Circle()
s2 = Point()
my_draw(s1)  # 正在畫一個圓
my_draw(s2)  # 正在畫一個點
示例1:
class MiniOS(object):
    """MiniOS 作業系統類 """
    def __init__(self, name):
        self.name = name
        self.apps = []  # 安裝的應用程式名稱串列

    def __str__(self):
        return "%s 安裝的軟體串列為 %s" % (self.name, str(self.apps))

    def install_app(self, app):
        # 判斷是否已經安裝了軟體
        if app.name in self.apps:
            print("已經安裝了 %s,無需再次安裝" % app.name)
        else:
            app.install()
            self.apps.append(app.name)


class App(object):
    def __init__(self, name, version, desc):
        self.name = name
        self.version = version
        self.desc = desc

    def __str__(self):
        return "%s 的當前版本是 %s - %s" % (self.name, self.version, self.desc)

    def install(self):
        print("將 %s [%s] 的執行程式復制到程式目錄..." % (self.name, self.version))


class PyCharm(App):
    pass


class Chrome(App):
    def install(self):
        print("正在解壓縮安裝程式...")
        super().install()


linux = MiniOS("Linux")
print(linux)
pycharm = PyCharm("PyCharm", "1.0", "python 開發的 IDE 環境")
chrome = Chrome("Chrome", "2.0", "谷歌瀏覽器")

linux.install_app(pycharm)
linux.install_app(chrome)
linux.install_app(chrome)
print(linux)
"""執行結果
    Linux 安裝的軟體串列為 []
    將 PyCharm [1.0] 的執行程式復制到程式目錄...
    正在解壓縮安裝程式...
    將 Chrome [2.0] 的執行程式復制到程式目錄...
    已經安裝了 Chrome,無需再次安裝
    Linux 安裝的軟體串列為 ['PyCharm', 'Chrome']
"""
示例2:

20.鴨子型別 Duck typing

    鴨子型別概述:
        1.一個物件有效的語意,不是由繼承自特定的類或實作特定的介面,而是由"當前方法和屬性的集合"決定
        2.鴨子型別是動態型別的一種風格,看著像鴨子,它就是鴨子
        3.鴨子型別源自鴨子測驗: 當看到一只鳥走起來像鴨子,游泳起來像鴨子,叫起來也像鴨子,那么這只鳥就可以被稱為鴨子
        4.鴨子型別中的規范全憑自覺,沒有強制規定,我們不需要關心物件是什么型別到底是不是鴨子,只需要關心物件的行為

# Srt,List,Tuple這些類都有相同的方法,那么這些類互稱鴨子
class Str:
    def index(self):
        pass


class List:
    def index(self):
        pass


class Tuple:
    def index(self):
        pass


s = Str()
s.index()

l = List()
l.index()

t = Tuple()
t.index()
# Str類,List類和Tuple類完全沒有耦合性,但是在某種意義上他們卻統一了一個標準
# 對相同的功能設定了相同的名字,這樣方便開發,這個方法就可以互成為鴨子型別
示例1:
# 用鴨子型別實作多型
class Duck:
    def quack(self):
        print "Duck imitate duck"
 

class Bird:
    def quack(self):
        print "bird imitate duck"
 

class Chicken:
    def quack(self):
        print "chicken imitate duck"
 

def in_the_forest(duck):
    duck.quack()
 

duck = Duck()
bird = Bird()
chicken = Chicken()
for x in [duck, bird, chicken]:
    in_the_forest(x)
示例2:

21.包裝(二次加工標準型別)

    包裝概述: 基于標準資料型別來定制我們自己的資料型別,新增/改寫方法

# 包裝 = 繼承 + 派生
class List(list):
    # 定義一個方法取串列中間值
    def show_midlle(self):
        min_index = int(len(self) / 2)
        return self[min_index]

    # 重寫串列的append方法,限制只允許添加字串
    def append(self, p_object):
        if type(p_object) is str:
            super().append(p_object)
        else:
            print("型別錯誤,只允許添加字串")

l1 = List("helloworld")
print(l1, type(l1))  # ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'] <class '__main__.List'>
print("串列%s的中間值是%s" %(l1, l1.show_midlle()))
# 串列['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']的中間值是w

l1.append("coco")
l1.append(123)  # 型別錯誤,只允許添加字串
print(l1)  # ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', 'coco']
示例1:
# 給clear加權限限制
class List(list):
    def __init__(self, item, tag=False):
        super().__init__(item)
        self.tag = tag

    def append(self, p_object):
        if not isinstance(p_object, str):
            raise TypeError
        super().append(p_object)

    def clear(self):
        if not self.tag:
            raise PermissionError
        super().clear()


l=List([1, 2, 3], False)
print(l)
print(l.tag)

l.append('saf')
print(l)

# l.clear() #例外
l.tag = True
l.clear()
示例2:

22.授權

    授權概述:
        1.授權是包裝的一個特性,包裝一個型別通常是對已存在的型別的一些定制
        2.授權的這種做法可以新建修改或洗掉原有產品的功能,其它的則保持原樣
        3.授權的程序,即所有更新的功能都是由新類的某部分來處理,但已存在的功能就授權給物件的默認屬性
        4.實作授權的關鍵點就是覆寫__getattr__方法

# 授權-->是組合的運用
import time

class Open:
    def __init__(self, filename, mode="r", encoding="utf-8"):
        self.filename = filename
        self.file = open(filename, mode, encoding=encoding)
        self.mode = mode
        self.encoding = encoding

    def write(self, line):
        t = time.strftime("%Y-%m-%d %X")
        self.file.write("%s %s" % (t, line))

    def __getattr__(self, item):
        return getattr(self.file, item, "沒有找到%s" % item)


f1 = Open("a.txt", "r+")
print(f1.file)  # <_io.TextIOWrapper name='a.txt' mode='r+' encoding='utf-8'>
print(f1.reads)  # 沒有找到reads
print(f1.read)  # <built-in method read of _io.TextIOWrapper object at 0x00000000056F51F8>
f1.write("hello world\n")
f1.seek(0)  # 移動檔案指標到檔案開頭
print("讀檔案%s內容是%s" % (f1.filename, f1.read()))  # 讀檔案a.txt內容是2020-07-31 10:54:27 hello world
示例1:
# 加上b模式支持
import time

class FileHandle:
    def __init__(self, filename, mode='r', encoding='utf-8'):
        if 'b' in mode:
            self.file = open(filename, mode)
        else:
            self.file = open(filename, mode, encoding=encoding)
        self.filename = filename
        self.mode = mode
        self.encoding = encoding

    def write(self, line):
        if 'b' in self.mode:
            if not isinstance(line, bytes):
                raise TypeError('must be bytes')
        self.file.write(line)

    def __getattr__(self, item):
        return getattr(self.file, item)

    def __str__(self):
        if 'b' in self.mode:
            res = "<_io.BufferedReader name='%s'>" %self.filename
        else:
            res = ("<_io.TextIOWrapper name='%s' mode='%s' encoding='%s'>" % 
                (self.filename, self.mode, self.encoding))
        return res
f1 = FileHandle('b.txt','wb')
# f1.write('你好啊')  # 自定制的write,不用在進行encode轉成二進制去寫了
f1.write('你好啊'.encode('utf-8'))
print(f1)  # <_io.BufferedReader name='b.txt'>
f1.close()
示例2:
class List:
    def __init__(self, seq):
        self.seq = seq

    def append(self, p_object):
        '派生自己的append加上型別檢查,覆寫原有的append'
        if not isinstance(p_object, int):
            raise TypeError('must be int')
        self.seq.append(p_object)

    @property
    def mid(self):
        '新增自己的方法'
        index = len(self.seq) // 2
        return self.seq[index]

    def __getattr__(self, item):
        return getattr(self.seq,item)

    def __str__(self):
        return str(self.seq)

l = List([1, 2, 3])
print(l)  # [1, 2, 3]
l.append(4)
print(l)  # [1, 2, 3, 4]
# l.append('33') # 會報錯,必須為int型別

print(l.mid)  # 3

# 基于授權,獲得insert方法
l.insert(0, -123)
print(l)  # [-123, 1, 2, 3, 4]
示例3:
class List:
    def __init__(self, seq, permission=False):
        self.seq = seq
        self.permission = permission

    def clear(self):
        if not self.permission:
            raise PermissionError('not allow the operation')
        self.seq.clear()

    def __getattr__(self, item):
        return getattr(self.seq, item)

    def __str__(self):
        return str(self.seq)


l = List([1, 2, 3])
# l.clear() # 此時沒有權限,拋出例外
l.permission = True
print(l)  # [1, 2, 3]
l.clear()  # l.clear()
print(l)  # []

#基于授權,獲得insert方法
l.insert(0, -123)
print(l)  # [-123]
示例4:

23.覆寫 override

    覆寫概述:
        1.覆寫是指在有繼承派生關系的類中,子類中實作了與基類(超類)同名的方法
        2.在子類實體呼叫方法時,實際呼叫的是子類中的覆寫版本,這種現象叫做覆寫

class A:
    def work(self):
        print("A類的work方法被呼叫")


class B(A):
    def work(self):
        print("B類的work方法被呼叫")


b = B()
b.work()  # 子類已經覆寫了父類的方法
示例:

24.函式重寫 overwrite

    函式重寫概述: 在自定義的類中,通過添加特定的方法,讓自定義的類實體化的物件能像內建物件一樣進行內建函式操作
    1.字串顯示函式重寫
        repr(obj) 回傳一個能代表此物件的字串的運算式(這個字串是給Python解釋器識別用的)
        repr(obj) 函式用于遠程通信資料校驗 例如: eval(repr(obj)) == obj
        str(obj) 通過給定的物件回傳一個字串(這個字串通常是給人閱讀的)
        repr(obj) 函式的重寫方法 def __repr__(self)
        str(obj) 函式的重寫方法 def __str__(self)
        當物件沒有 __str__方法時, 則回傳__repr__(self)的值

class B:
    def __str__(self):
     return 'str : class B'

    def __repr__(self):
     return 'repr : class B'


b=B()
print('%s'%b)  # str : class B
print('%r'%b)  # repr : class B
示例:

    2.內建函式重寫
        obj.__abs__() 對應 abs(obj)
        obj.__len__() 對應 len(obj)
        obj.__reversed__() 對應 reversed(obj)
        obj.__round__() 對應 round(obj)

# 此示例示意 abs(obj) 函式的重寫方法 obj.__abs__() 方法的使用
class MyInteger:
    def __init__(self, value):
        self.data = value

    def __repr__(self):
        return 'MyInteger(%d)' % self.data

    def __abs__(self):
        if self.data < 0:
            return MyInteger(-self.data)  # 創建一個新的以物件并回傳
        return MyInteger(self.data)

    def __len__(self):
        '''len(x)函式規定只能回傳整數值,因此此方法不能回傳字串等其它型別的值'''
        return 100
        

I1 = MyInteger(-10)
print(I1)   # <-- 此處等同于print(str(I1))
I2 = abs(I1)  # I2 = MyInteger(10)
print(I2)  # MyInteger(10)
print(len(I1))  # I1.__len__()
示例:

    3.數值轉換函式重寫
        obj.__complex__() 對應 complex(obj)
        obj.__int__() 對應 int(obj)
        obj.__float__() 對應 float(obj)
        obj.__bool__() 對應 bool(obj)

    4.布爾測驗函式的重寫
        布爾測驗函式概述:
            1.用于bool(obj)函式取值,用于if陳述句真值運算式中,用于while陳述句真值運算式中
            2.布測驗式方法的查找順序是 __bool__方法,其次是__len__方法,如果都沒有則回傳True
            3.語法:
                def __bool__(self):
                    pass

# 此示例示意 bool 真值測驗函式的重寫
class MyList:
    '''定義一個容器類,用于存盤任意型別的資料其內部的存盤方式用list實作'''
    def __init__(self, iterable):
        self.data = [x for x in iterable]

    def __repr__(self):
        return 'MyList(%s)' % self.data

    def __len__(self):
        print("__len__ 方法被呼叫!")
        return len(self.data)  # 回傳串列的長度

    def __bool__(self):
        print('__bool__方法被呼叫')
        '''此方法用于bool(obj) 函式取值,優先取此函式的回傳值,此方法用于定義bool(obj)的取值規則'''
        # 規則,所有元素的和為0,則回傳False否則回傳True
        return sum(self.data) != 0


myl = MyList([1, -2, 5, -4])
print(myl)  # MyList([1, -2, 5, -4])
print('bool(myl) =', bool(myl))
if myl:
    print('myl 的布林值為True')
else:
    print('myl 的布林值為False')
示例:

    5.自定制格式化字串重寫 __format__

format_dict = {
    'nat':'{obj.name}-{obj.addr}-{obj.type}',  # 學校名-學校地址-學校型別
    'tna':'{obj.type}:{obj.name}:{obj.addr}',  # 學校型別:學校名:學校地址
    'tan':'{obj.type}/{obj.addr}/{obj.name}',  # 學校型別/學校地址/學校名
}
class School:
    def __init__(self, name, addr, type):
        self.name = name
        self.addr = addr
        self.type = type

    def __repr__(self):
        return 'School(%s,%s)' %(self.name, self.addr)
    def __str__(self):
        return '(%s,%s)' %(self.name, self.addr)

    def __format__(self, format_spec):
        # if format_spec
        if not format_spec or format_spec not in format_dict:
            format_spec = 'nat'
        fmt = format_dict[format_spec]
        return fmt.format(obj=self)


s1 = School('oldboy1', '北京', '私立')
print('from repr: ',repr(s1))
print('from str: ',str(s1))
print(s1)
'''
    str函式或者print函式--->obj.__str__();repr或者互動式解釋器--->obj.__repr__()
    如果__str__沒有被定義,那么就會使用__repr__來代替輸出,這倆方法的回傳值必須是字串,否則拋出例外
'''
print(format(s1, 'nat'))
print(format(s1, 'tna'))
print(format(s1, 'tan'))
print(format(s1, 'asfdasdffd'))
示例:

    6.反射函式重寫

class Foo():
    x = 1
    def __init__(self):
        self.y = 1

    def __getattr__(self, item):
        print("你要找的%s屬性不存在" % item)

    # 重寫內置洗掉方法,限制洗掉條件
    def __delattr__(self, item):
        print("執行了洗掉%s屬性的操作" % item)
        self.__dict__.pop(item)

    # 重寫內置設定方法,限制設定條件
    def __setattr__(self, key, value):
        print("你執行了設定%s屬性值為%s的操作" %(key, value))
        self.__dict__[key] = value


f1 = Foo()
f1.x = 10
f1.name = "coco"  # 設定屬性時會觸發__setattr__

print(f1.z)  # 屬性不存在時,會自動觸發__getattr__
del f1.y  # 洗掉屬性時,會觸發__delattr__

print(f1.__dict__)
示例:

25.運算子多載

    運算子多載概述:
        1.讓自定義的類實體化的對像能夠使用運算子進行操作,像數學運算式一樣進行運算操作讓程式簡潔易讀
        2.運算子多載方法的引數已經有固定的含義,不建議改變原有的含義
    1.算術運算子
        方法名 運算子
        __add__ 加法 +
        __sub__ 減法 -
        __mul__ 乘法 *
        __truediv__ 除法 /
        __floordiv__ 地板除 //
        __mod__ 取模(求余) %
        __pow__ 冪 **
        二元運算子多載方法格式:
            def __xxx__(self, other):
                pass

# 此程式示意運算子多載
class MyNumber:
    def __init__(self, v):
        self.data = v

    def __repr__(self):
        return "MyNumber(%d)" % self.data

    def __add__(self, other):
        print("__add__方法被呼叫")
        obj = MyNumber(self.data + other.data)
        return obj

    def __sub__(self, other):
        return MyNumber(self.data - other.data)


n1 = MyNumber(100)
n2 = MyNumber(200)
# n3 = n1.__add__(n2)
n3 = n1 + n2  # 等同于 n1.__add__(n2)
print(n3)
n4 = n2 - n1
print('n4 =', n4)  # MyNumber(100)
示例1:
# 自定義物件的加法運算子多載規則
class MyType:
    """實作物件中*號求和"""
    def __init__(self, s):
        self.s = s

    def __add__(self, other):
        return self.s.count('*') + other.s.count('*')


obj1 = MyType('ccasdd***2343*****')
obj2 = MyType('vvsvvndk***3423**6517***')
print(obj1 + obj2)
print(obj1.__add__(obj2))
示例2:

    2.反向算術運算子
        方法名 運算子
        __radd__ 加法 +
        __rsub__ 減法 -
        __rmul__ 乘法 *
        __rtruediv__ 除法 /
        __rfloordiv__ 地板除 //
        __rmod__ 取模(求余) %
        __rpow__ 冪 **

# 此示例示意返向算術運算子的多載
class MyList:
    def __init__(self, iterable):
        self.data = [x for x in iterable]

    def __repr__(self):
        # %r 等同與用repr函式取值--> repr(self.data)
        return 'MyList(%r)' % self.data

    def __mul__(self, rhs):
        return MyList(self.data * rhs)

    def __rmul__(self, lhs):
        print("__rmul__被呼叫, lhs=", lhs)
        return MyList(self.data * lhs)  # lhs (left hand side)


L1 = MyList([1, 2, 3])
L2 = MyList(range(4, 7))
L4 = L1 * 2  # 實作乘法運算呼叫的是自定義的__mul__方法
print('L4 =', L4)  # MyList([1,2,3,1,2,3])
L5 = 2 * L1  # 此時呼叫的是自定義的反向乘法運算子多載__rmul__方法
print(L5)
示例:

    3.復合賦值運算子多載
        方法名 運算子
        __iadd__ 加法 +=
        __isub__ 減法 -=
        __imul__ 乘法 *=
        __itruediv__ 除法 /=
        __ifloordiv__ 地板除 //=
        __imod__ 取模(求余) %=
        __ipow__ 冪 **=

示例:

# 此示例示意復合賦值算術運算子的多載
class MyList:
    def __init__(self, iterable):
        self.data = [x for x in iterable]

    def __repr__(self):
        return 'MyList(%r)' % self.data

    def __add__(self, rhs):
        print("__add__方法被呼叫")
        return MyList(self.data + rhs.data)

    def __iadd__(self, rhs):
        print("__iadd__方法被呼叫")
        self.data.extend(rhs.data)
        return self

L1 = MyList([1, 2, 3])
L2 = MyList(range(4, 7))
print("id(L1) =", id(L1))
# +=優先呼叫__iadd__方法,沒有再呼叫__add__方法
L1 += L2  # 相當于 L1 = L1 + L2
print('L1 =', L1)
print("id(L1) =", id(L1))
示例:

    4.比較的運算子的多載
        __lt__ < 小于
        __le__ <= 小于等于
        __gt__ > 大于
        __ge__ >= 大于等于
        __eq__ == 等于
        __ne__ != 不等于
        比較運算子通常回傳True或False

    5.位運算子多載
        __inert__ ~ 取反(一元運算子)
        __and__ & 按位與(交集)
        __or__ | 按位或(并集)
        __xor__ ^ 按位異或(對稱補集)
        __lshift__ << 左移
        __rshift__ >> 右移

    6.反向位運算子多載
        __rand__ & 按位與(交集)
        __ror__ | 按位或(并集)
        __rxor__ ^ 按位異或(對稱補集)
        __rlshift__ << 左移
        __rrshift__ >> 右移

    7.復合賦值運算子多載
        __iand__ &= 按位與(交集)
        __ior__ |= 按位或(并集)
        __ixor__ ^= 按位異或(對稱補集)
        __ilshift__ <<= 左移
        __irshift__ >>= 右移

    8.一元運算子的多載
        __neg__ - 負號
        __pos__ + 正號
        __invert__ ~ 按位取反
        格式:
            def __xxx__(self):
                pass

# 此示例示意一元運算子的多載
class MyList:
    def __init__(self, iterable):
        self.data = [x for x in iterable]

    def __repr__(self):
        return 'MyList(%r)' % self.data

    def __neg__(self):
        print("__neg__方法被呼叫!")
        L = (-x for x in self.data)
        return MyList(L)


L1 = MyList([1, -2, 3, -4, 5])
print("L1 =", L1)
L2 = -L1
print("L2 =", L2)
示例:

    9.成員運算子的多載
        in
        not in 相當于 in 取反,所有只需要多載 in 即可
        格式:
            def __contains__(self, e):  # e代表元素
                pass

# 此示例示意 in / not in 運算子的多載
class MyList:
    def __init__(self, iterable):
        self.data = [x for x in iterable]

    def __repr__(self):
        return 'MyList(%r)' % self.data

    def __contains__(self, e):  # e 代表測驗元素
        print("__contains__被呼叫")
        for x in self.data:
            if e == x:  # 如果相同,則說明e在串列中
                return True
        return False


L1 = MyList([1, -2, 3, -4, 5])
if 2 in L1:  # 需要多載 __contains__ 方法
    print("2在L1中")
else:
    print("2不在L1中")
示例:

    10.索引和切片運算子的多載
        多載方法: 讓自定義的型別的物件能夠支持索引和切片操作
            __getitem__(self, i) 用于索引/切片取值
            __setitem__(self, i) 用于索引/切片賦值
            __delitem__(self, i) 用于del陳述句洗掉索引操作

# 此示例示意索引 index 和切片 slice 運算子的多載
class MyList:
    def __init__(self, iterable):
        self.data = [x for x in iterable]

    def __repr__(self):
        return "MyList(%r)" % self.data

    def __getitem__(self, i):
        print("__getitem__被呼叫", i)
        if type(i) is slice:
            print("正在進行切片操作")
        elif type(i) is int:
            print("正在進行索引操作")
        return self.data[i]

    def __setitem__(self, i, v):
        print("__setitem__被呼叫", i, v)
        self.data[i] = v

    def __delitem__(self, i):
        print("__delitem__被呼叫", i)
        del self.data[i]

L1 = MyList([1, -2, 3, -4, 5])
# 切片操作呼叫的是__getitem__方法,L1[0:2]等同于L1[slice(0, 2, None)]
print(L1[0:2])  # [1, -2]
print(L1[2])  # 3
L1[1] = 2  # MyList([1, 2, 3, -4, 5])
del L1[:2]
print(L1)  # MyList([3, -4, 5])
示例:

26.類裝飾器

    1.類的裝飾器無引數示例

def decorate(cls):
    print('類的裝飾器開始運行啦------>')
    return cls


@decorate  # 無參:People=decorate(People)
class People:
    def __init__(self, name, age, salary):
        self.name = name
        self.age = age
        self.salary = salary


p1=People('egon', 18, 3.3)
示例:

    2.類的裝飾器有引數示例

def typeassert(**kwargs):
    def decorate(cls):
        print('類的裝飾器運行:', kwargs)
        return cls
    return decorate


# 有參:1.運行typeassert(...)回傳結果是decorate,此時引數都傳給kwargs
# 有參:2.People=decorate(People)
@typeassert(name=str, age=int, salary=float)
class People:
    def __init__(self, name, age, salary):
        self.name = name
        self.age = age
        self.salary = salary


p1=People('egon', 18, 3.3)  # 類的裝飾器運行:{'name': <class 'str'>, 'age': <class 'int'>, 'salar': <class 'float'>}
示例1:
class Test(object):
    def __init__(self, func):
        print("---初始化---")
        print("func name is %s" % func.__name__)
        self.__func = func

    def __call__(self):
        print("---裝飾器中的功能---")
        self.__func()
"""說明:
    1.用Test來裝作裝飾器對test函式進行裝飾的時,先創建Test的實體物件,再把test這個函式名當做引數傳遞到__init__方法中
        即在__init__方法中的屬性__func指向了test指向的函式,而test則指向了用Test創建出來的實體物件
    2.當在使用test()進行呼叫時,就相當于讓這個物件(),因此會呼叫這個物件的__call__方法
    3.為了能夠在__call__方法中呼叫原來test指向的函式體,在__init__方法中需要一個實體屬性來保存這個函式體的參考
        所以才有了self.__func = func這句代碼,從而在呼叫__call__方法中能夠呼叫到test之前的函式體
 """

@Test
def test():
    print("----test---")


test()
"""執行結果
    ---初始化---
    func name is test
    ---裝飾器中的功能---
    ----test---
"""
示例2:

    3.描述符裝飾器示例

class Typed:
    def __init__(self, key, expected_type):
        self.key = key
        self.expected_type = expected_type
        
    def __get__(self, instance, owner):
        print('get方法')
        # print('instance引數【%s】' % instance)
        # print('owner引數【%s】' % owner)
        return instance.__dict__[self.key]
        
    def __set__(self, instance, value):
        print('set方法')
        # print('instance引數【%s】' % instance)
        # print('value引數【%s】' % value)
        # print('====>', self)
        if not isinstance(value, self.expected_type):
            # print('你傳入的型別不是字串,錯誤')
            # return
            raise TypeError('%s 傳入的型別不是%s' % (self.key, self.expected_type))
        instance.__dict__[self.key] = value
        
    def __delete__(self, instance):
        print('delete方法')
        # print('instance引數【%s】' % instance)
        instance.__dict__.pop(self.key)


def deco(**kwargs):
    def wrapper(obj):
        for key,val in kwargs.items():
            print("-->", key, val)
            setattr(obj, key, Typed(key, val))
        return obj
    return wrapper


@deco(name=str, age=int)
class People:
    def __init__(self, name, age, salary):
        self.name = name
        self.age = age
        self.salary = salary


p1 = People('coco', 13, 13.3)
print(p1.__dict__)
"""執行結果
    --> name <class 'str'>
    --> age <class 'int'>
    set方法
    set方法
    {'name': 'coco', 'age': 13, 'salary': 13.3}
"""
示例:

    4.類裝飾函式示例

class Test:
    def __init__(self, func):
        # 要使__call__方法中呼叫原來get_str指向的函式體,需要在__init__方法中就需要一個實體屬性來保存這個函式體的參考
        self.__func = func

    def __call__(self):
        print("Test類裝飾的內容")
        return self.__func()


# 用Test來裝作裝飾器對get_str函式進行裝飾的時候,首先會創建Test的實體物件
# 然后把get_str這個函式名當做引數傳遞到__init__方法中的屬性__func指向了get_str指向的函式
@Test  # 等同于get_str = Test(get_str)
def get_str():
    print("this is get_str function")
    return "ok"


# get_str指向了用Test創建出來的實體物件,當在使用get_str()進行呼叫時
# 就相當于讓這個物件(),因此會呼叫這個物件的__call__方法
ret = get_str()
print(ret)
"""執行結果
    Test類裝飾的內容
    this is get_str function
    ok
"""
示例:

27.類的約束-抽象類(介面類)

    1.抽象類概述:
        1.抽象類的主要功能就是定制一個規范,讓其子類必須按照此規范實作,抽象類本身不能被實體化
        2.制定了一個規范,讓繼承父類的子類必須實作父類的抽象方法,如果子類沒有實作父類的抽象方法則子類實體化物件時報錯
        3.抽象類和介面類做的事情: 制定一個類的metaclass是ABCMeta那么這個類就變成了一個抽象類
        4.Python中有原生實作抽象類的方法,但沒有原生實作介面類的方法
        5.在Java來區分抽象類和介面類
            1.抽象類: 只能被子類單繼承,抽象類的方法可以實作
            2.介面類: 可以被子類多繼承,介面類的所有方法都不應該實作,只定義方法后用pass占位
            3.抽象類和介面類只需要知道區分,不用按照Java規定去寫Python中的代碼

from abc import ABCMeta
from abc import abstractmethod


class Payment(metaclass=ABCMeta):  # 抽象類規范和約束,metaclass指定的是一個元類
    @abstractmethod
    def pay(self):  # 抽象方法
        pass


class Alipay(Payment):
    def __init__(self,money):
        self.money = money

    def pay(self):
        print('使用支付寶支付了%s' %self.money)


class Jdpay(Payment):
    def __init__(self, money):
        self.money = money

    def pay(self):
        print('使用京東支付了%s' % self.money)

class Wechatpay(Payment):

    def __init__(self,money):
        self.money = money

    def pay(self):
        print('使用微信支付了%s' % self.money)


def pay(obj):
    obj.pay()
    
    
# 子類中沒有實作pay方法時,子類實體化物件時會報錯
w1 = Wechatpay(200)
a1 = Alipay(200)
j1 = Jdpay(100)

# 統一化介面設計,也叫歸一化設計: 不管是哪一個類的物件,都呼叫同一個函式去完成相似的功能
pay(a1)  # 使用支付寶支付了200
pay(j1)  # 使用京東支付了100
示例1:
# 用元類的思想來實作約束時子類必須實作pay方法
class Payment:
    """此類什么都不做,就是制定一個標準,誰繼承我就必須定義我里面的方法"""
    
    def pay(self, money):
        raise Exception("你沒有實作pay方法")


class QQpay(Payment):
    def pay(self, money):
        print('使用qq支付%s元' % money)


class Alipay(Payment):
    def pay(self, money):
        print('使用阿里支付%s元' % money)


class Wechatpay(Payment):
    def fuqian(self, money):
        print('使用微信支付%s元' % money)


def pay(obj,money):
    obj.pay(money)


a = Alipay()
b = QQpay()
c = Wechatpay()
pay(a, 100)  # 使用阿里支付100元
pay(b, 200)  # 使用qq支付200元
pay(c, 300)  # Exception: 你沒有實作pay方法
示例2:

28.類的約束-元類

    1.元類概述:
        1.元類就是用來創建這些類(物件)的,元類就是類的類,type就是Python在背后用來創建所有類的元類
        2.自定義元類目的是攔截類的創建, 修改類, 回傳修改之后的類
        3.類中有一個屬性 __metaclass__ 其用來表示該類由誰來實體化創建,可以用該屬性設定一個type類的派生類,從而查看類創建的程序
        4.type可以動態創建類,type(類名, 由父類名稱組成的元組(針對繼承的情況,可以為空), 包含屬性的字典(名稱和值))
        5.元類創建類,元類創建元類驗證

class A:
    pass


a = A()
a.__class__  # __main__.A
a.__class__.__class__  # type
a.__class__.__class__.__class__  # type
示例:

    2.type動態創建類

Test = type("Test", (), {"num1": 100, "num2": 200})
Test.__dict__
obj = Test()
obj.num1
obj.num2
"""執行結果
    mappingproxy({'num1': 100,
                  'num2': 200,
                  '__module__': '__main__',
                  '__dict__': <attribute '__dict__' of 'Test' objects>,
                  '__weakref__': <attribute '__weakref__' of 'Test' objects>,
                  '__doc__': None})
    100
    200
"""
示例:

    3.較為完整的使用type創建類的方式

class A(object):
    num = 100


def print_b(self):
    print("實例方法呼叫", self.num)


@staticmethod
def print_static():
    print("----靜態方法呼叫-----")


@classmethod
def print_class(cls):
    print("類方法呼叫", cls.num)


B = type("B", (A,), {"print_b": print_b, "print_static": print_static, "print_class": print_class})
b = B()
b.print_b()  # 實體方法呼叫 100
b.print_static()  # ----靜態方法呼叫----
b.print_class()  # 類方法呼叫 100
示例:

    4.自定義元類的 __init__ 和 __call__ 方法

class MyType(type):
    def __init__(self, a, b, c):
        print("a:", a)  # a: Foo
        print("b:", b)  # b: ()
        print("c:", c)
        # c: {'__module__': '__main__', '__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x102ead560>}
        print("元類初始化執行完成")  # 元類初始化執行完成

    def __call__(self, *args, **kwargs):
        print(args, kwargs)  # ('coco', 18) {}
        obj = object.__new__(self)  # object.__new__(Foo)-->f1
        self.__init__(obj, *args, **kwargs)  # Foo.__init__(f1, *args, **kwargs)
        return obj


class Foo(object, metaclass=MyType):  # Foo=MyType(Foo, "Foo", (), {})-->__init__
    def __init__(self, name, age):
        self.name = name
        self.age = age


f1 = Foo("coco", 18)
print(f1)  # <__main__.Foo object at 0x00000000055BF6A0>
print(f1.__dict__)  # {'name': 'coco', 'age': 18}
示例:

    5.自定義元類的 __new__ 方法

class UpperAttrMetaClass(type):
    # __new__ 是在__init__之前被呼叫的特殊方法,很少用到__new__,除非希望能夠控制物件的創建
    # __new__是用來創建物件并回傳的方法,而__init__只是用來將傳入的引數初始化給物件
    def __new__(cls, class_name, class_parents, class_attr):
        # 遍歷屬性字典,把不是__開頭的屬性名字變為大寫
        new_attr = {}
        for name, value in class_attr.items():
            if not name.startswith("__"):
                new_attr[name.upper()] = value

        # 方法1: 通過'type'來做類物件的創建
        return type(class_name, class_parents, new_attr)

        # 方法2: 復用type.__new__方法,這就是基本的OOP編程,沒什么魔法
        # return type.__new__(cls, class_name, class_parents, new_attr)

# python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):
    bar = 'bip'

# python2的用法
# class Foo(object):
#     __metaclass__ = UpperAttrMetaClass
#     bar = 'bip'


print(hasattr(Foo, 'bar'))  # False
print(hasattr(Foo, 'BAR'))  # True

f = Foo()
print(f.BAR)  # bip
示例:

29.元類的應用-ORM

    1.ORM概述:
        1.ORM是python編程語言后端web框架Django的核心思想"Object Relational Mapping",即物件-關系映射,簡稱ORM
        2.創建一個實體物件,用創建它的類名當做資料表名,用創建它的類屬性對應資料表的欄位,當對這個實體物件操作時,能夠對應MySQL陳述句
        3.ORM就是讓開發者在操作資料庫的時候,能夠像操作物件時通過xxxx.屬性=yyyy一樣簡單

    2.通過元類簡單實作ORM中的insert功能

class ModelMetaclass(type):
    def __new__(cls, name, bases, attrs):
        mappings = dict()
        # 判斷是否需要保存
        for k, v in attrs.items():
            # 判斷是否是指定的StringField或者IntegerField的實體物件
            if isinstance(v, tuple):
                print('Found mapping: %s ==> %s' % (k, v))
                mappings[k] = v

        # 洗掉這些已經在字典中存盤的屬性
        for k in mappings.keys():
            attrs.pop(k)

        # 將之前的uid/name/email/password以及對應的物件參考,類名字
        attrs['__mappings__'] = mappings  # 保存屬性和列的映射關系
        attrs['__table__'] = name  # 假設表名和類名一致
        return type.__new__(cls, name, bases, attrs)


class Model(object, metaclass=ModelMetaclass):
    def __init__(self, **kwargs):
        for name, value in kwargs.items():
            setattr(self, name, value)

    def save(self):
        fields = []
        args = []
        for k, v in self.__mappings__.items():
            fields.append(v[0])
            args.append(getattr(self, k, None))

        args_temp = list()
        for temp in args:
            # 判斷入如果是數字型別
            if isinstance(temp, int):
                args_temp.append(str(temp))
            elif isinstance(temp, str):
                args_temp.append("""'%s'""" % temp)
        sql = ('insert into %s (%s) values (%s)' % 
            (self.__table__, ','.join(fields), ','.join(args_temp)))
        print('SQL: %s' % sql)


class User(Model):
    uid = ('uid', "int unsigned")
    name = ('username', "varchar(30)")
    email = ('email', "varchar(30)")
    password = ('password', "varchar(30)")


# 實體化物件首先會呼叫元類ModelMetaclass的__new__構造方法,再呼叫父類Model的__init__初始化方法
u = User(uid=12345, name='Michael', email='[email protected]', password='my-pwd')
# print(u.__dict__)
u.save()
示例:

30.即時通訊和微信面向物件設計示例

    1.騰訊即時通信模塊,初級封裝

#! /usr/bin/env python
# coding: utf-8

import random
import time


class Message(object):

    def __init__(self, msgarr=[], toacc=''):
        self.msgbody = msgarr  # 此處為MsgDict物件實體的串列或者空串列
        self.toacc = toacc  # toacc為字串(單發)或者串列(批量發)
        self.msgrandom = random.randint(1, 1000000000)
        self.msgrequest = {
            'To_Account': toacc,  # 訊息接收方賬號
            'MsgRandom': self.msgrandom,  # 訊息亂數,由隨機函式產生
            'MsgBody': [t.msg for t in msgarr]
        }

    def del_option(self, option):
        if option in (set(self.msgrequest) - set(['To_Account', 'MsgRandom', 'MsgBody'])):
            self.__dict__.pop(option)
            self.msgrequest.pop(option)

    def append_msg(self, msg):
        self.msgbody.append(msg)
        self.msgrequest['MsgBody'].append(msg.msg)

    def insert_msg(self, index, msg):
        self.msgbody.insert(index, msg)
        self.msgrequest['MsgBody'].insert(msg.msg)

    def del_msg(self, index):
        if index in range(len(self.msgbody)):
            del self.msgbody[index]
            del sel.msgrequest['MsgBody'][index]

    def set_from(self, fromacc):
        #  指定訊息的發送方,默認為服務器發送
        self.fromacc = fromacc
        self.msgrequest['From_Account'] = fromacc

    def set_to(self, toacc):
        #  指定訊息的接收方,可以為String(單發),可以為List(批量發送)
        self.toacc = toacc
        self.msgrequest['To_Account'] = toacc

    def refresh_random(self):
        self.msgrandom = random.randint(1, 1000000000)
        self.msgrequest['MsgRandom'] = self.msgrandom,  # 訊息亂數,由隨機函式產生

    def set_sync(self, sync):
        # 同步選項: 1, 把訊息同步到From_Account在線終端和漫游上
        #           2, 訊息不同步至From_Account
        #           若不填寫,默認情況下會將訊息同步
        #           僅在單發單聊訊息中可呼叫
        self.sync = sync
        self.msgrequest['SyncOtherMachine'] = sync

    def set_timestamp(self):
        # 設定訊息時間戳,unix時間, 僅在單發單聊訊息中可以呼叫
        self.timestamp = int(time.time())
        self.msgrequest['MsgTimeStamp'] = self.timestamp

    def set_offlinepush(self, pushflag=0, desc='', ext='', sound=''):
        # 僅適用于APNa推送,不適用于安卓廠商推送
        self.msgrequest['OfflinePushInfo'] = {
            'PushFlag': pushflag,
            'Desc': desc,
            'Ext': ext,
            'Sound': sound
        }


class MsgDict(object):

    def __init__(self, msgtype='', msgcontent={}):
        self.msgtype = msgtype
        self.msgcontent = msgcontent

    @property
    def msg(self):
        return {
            'MsgType': self.msgtype,
            'MsgContent': self.msgcontent
        }

    def set_content(self, content):
        self.msgcontent = content


class TextMsg(MsgDict):

    def __init__(self, text='', msgtype='TIMTextElem'):
        self.text = text
        content = {'Text': text}
        super(TextMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_text(self, text):
        self.text = text
        self.msgcontent['Text'] = text


class LocationMsg(MsgDict):

    def __init__(self, desc='', latitude=0, longitude=0, msgtype='TIMLocationElem'):
        self.desc = desc
        self.latitude = latitude
        self.longitude = longitude
        content = {
            'Desc': desc,  # 地理位置描述資訊, String
            'Latitude': latitude,  # 緯度, Number
            'Longitude': longitude  # 經度, Number
        }
        super(LocationMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_desc(self, desc):
        self.desc = desc
        self.msgcontent['Desc'] = desc

    def set_location(self, latitude, longitude):
        self.latitude = latitude
        self.longitude = longitude
        self.msgcontent['Latitude'] = latitude
        self.msgcontent['Longitude'] = longitude

    def set_latitude(self, latitude):
        self.latitude = latitude
        self.msgcontent['Latitude'] = latitude

    def set_longitude(self, longitude):
        self.longitude = longitude
        self.msgcontent['Longitude'] = longitude


class FaceMsg(MsgDict):

    def __init__(self, index=1, data=https://www.cnblogs.com/tangxuecheng/p/'', msgtype='TIMFaceElem'):
        self.index = index
        self.data = data
        content = {
            'Index': index,  # 表情索引,用戶自定義, Number
            'Data': data  # 額外資料, String
        }
        super(TextMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_index(self, index):
        self.index = index
        self.msgcontent['Index'] = index

    def set_data(self, data):
        self.data = data
        self.msgcontent['Data'] = data


class CustomMsg(MsgDict):

    def __init__(self, data=https://www.cnblogs.com/tangxuecheng/p/'', desc='', ext='', sound='', msgtype='TIMCustomElem'):
        self.data = data
        self.desc = desc
        self.ext = ext
        self.sound = sound
        content = {
            'Data': data,  # 自定義訊息資料,不作為APNS的payload中欄位下發,故從payload中無法獲取Data欄位, String
            'Desc': desc,  # 自定義訊息描述,當接收方為iphone后臺在線時,做ios離線Push時文本展示
            'Ext': ext,  # 擴展欄位,當接收方為ios系統且應用處在后臺時,此欄位作為APNS請求包Payloads中的ext鍵值下發,Ext的協議格式由業務方確定,APNS只做透傳
            'Sound': sound  # 自定義APNS推送鈴聲
        }
        super(CustomMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_data(self, data):
        self.data = data
        self.msgcontent['Data'] = data

    def set_desc(self, desc):
        self.desc = desc
        self.msgcontent['Desc'] = desc

    def set_ext(self, ext):
        self.ext = ext
        self.msgcontent['Ext'] = ext

    def set_sound(self, sound):
        self.sound = sound
        self.msgcontent['Sound'] = sound


class SoundMsg(MsgDict):

    def __init__(self, uuid='', size=0, second=0, msgtype='TIMSoundElem'):
        self.uuid = uuid
        self.size = size
        self.second = second
        content = {
            'UUID': uuid,  # 語音序列號,后臺用于索引語音的鍵值,String
            'Size': size,  # 語音資料大小, Number
            'Second': second  # 語音時長,單位秒 Number
        }
        super(SoundMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_uuid(self, uuid):
        self.uuid = uuid
        self.msgcontent['UUID'] = uuid

    def set_size(self, size):
        self.size = size
        self.msgcontent['Size'] = size

    def set_second(self, second):
        self.second = second
        self.msgcontent['Second'] = second


class ImageMsg(MsgDict):

    def __init__(self, uuid='', imgformat=0, imginfo=[], msgtype='TIMImageElem'):
        self.uuid = uuid
        self.imgformat = imgformat
        self.imginfo = imginfo
        content = {
            'UUID': uuid,  # 圖片序列號,后臺用于索引語音的鍵值,String
            'ImageFormat': imgformat,  # 圖片格式, BMP=1, JPG=2, GIF=3, 其他=0, Number
            'ImageInfoArray': [t.info for t in imginfo]  # 原圖,縮略圖或者大圖下載資訊, Array
        }
        super(ImageMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_uuid(self, uuid):
        self.uuid = uuid
        self.msgcontent['UUID'] = uuid

    def set_format(self, imgformat):
        self.imgformat = imgformat
        self.msgcontent['ImageFormat'] = imgformat

    def append_info(self, info):
        # info 為ImageInfo物件實體
        self.imginfo.append(info)
        self.msgcontnet['ImageInfoArray'].append(info.info)

    def insert_info(self, index, info):
        self.imginfo.insert(index, info)
        self.msgcontent['ImageInfoArray'].insert(index, info.info)

    def del_info(self, index):
        del self.imginfo[index]
        del self.msgcontent['ImageInfoArray'][index]


class FileMsg(MsgDict):

    def __init__(self, uuid='', size=0, name='', msgtype='TIMFileElem'):
        self.uuid = uuid
        self.size = size
        self.name = name
        content = {
            'UUID': uuid,  # 檔案序列號,后臺用于索引語音的鍵值,String
            'FileSize': size,  # 檔案資料大小, Number
            'FileName': name  # 檔案名稱/路徑, String
        }
        super(FileMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_uuid(self, uuid):
        self.uuid = uuid
        self.msgcontent['UUID'] = UUID

    def set_size(self, size):
        self.size = size
        self.msgcontent['FileSize'] = size

    def set_name(self, name):
        self.name = name
        self.msgcontent['FileName'] = name


class ImageInfo(object):

    def __init__(self, itype=1, size=0, width=0, height=0, url=''):
        # 圖片型別, 1-原圖, 2-大圖, 3-縮略圖, 0-其他
        self.itype = itype
        # 圖片資料大小,Number
        self.size = size
        # 圖片寬度,Number
        self.width = width
        # 圖片高度, Number
        self.height = height
        # 圖片下載地址,String
        self.url = url

    @property
    def info(self):
        return {
            'Type': self.itype,
            'Size': self.size,
            'Width': self.width,
            'Height': self.height,
            'URL': self.url
        }

    def set_type(self, itype):
        self.itype = itype

    def set_size(self, size):
        self.size = size

    def set_width(self, width):
        self.width = width

    def set_height(self, height):
        self.height = height

    def set_url(self, url):
        self.url = url
示例:

    2.微信開發包,python實作wechat_sdk開發

from __future__ import unicode_literals

import time

from wechat_sdk.exceptions import NeedParamError
from wechat_sdk.lib.crypto import BasicCrypto
from wechat_sdk.lib.request import WechatRequest
from wechat_sdk.utils import disable_urllib3_warning


class WechatConf(object):
    """ WechatConf 配置類

    該類將會存盤所有和微信開發相關的配置資訊, 同時也會維護配置資訊的有效性.
    """

    def __init__(self, **kwargs):
        """
        :param kwargs: 配置資訊字典, 可用字典 key 值及對應解釋如下:
                       'token': 微信 Token

                       'appid': App ID
                       'appsecret': App Secret

                       'encrypt_mode': 加解密模式 ('normal': 明文模式, 'compatible': 兼容模式, 'safe': 安全模式(默認))
                       'encoding_aes_key': EncodingAESKey 值 (傳入此值必須保證同時傳入 token, appid, 否則拋出例外)

                       'access_token_getfunc': access token 獲取函式 (用于單機及分布式環境下, 具體格式參見檔案)
                       'access_token_setfunc': access token 寫入函式 (用于單機及分布式環境下, 具體格式參見檔案)
                       'access_token_refreshfunc': access token 重繪函式 (用于單機及分布式環境下, 具體格式參見檔案)
                       'access_token': 直接匯入的 access token 值, 該值需要在上一次該類實體化之后手動進行快取并在此處傳入, 如果不
                                       傳入, 將會在需要時自動重新獲取 (傳入 access_token_getfunc 和 access_token_setfunc 函式
                                       后將會自動忽略此處的傳入值)
                       'access_token_expires_at': 直接匯入的 access token 的過期日期, 該值需要在上一次該類實體化之后手動進行快取
                                                  并在此處傳入, 如果不傳入, 將會在需要時自動重新獲取 (傳入 access_token_getfunc
                                                  和 access_token_setfunc 函式后將會自動忽略此處的傳入值)

                       'jsapi_ticket_getfunc': jsapi ticket 獲取函式 (用于單機及分布式環境下, 具體格式參見檔案)
                       'jsapi_ticket_setfunc': jsapi ticket 寫入函式 (用于單機及分布式環境下, 具體格式參見檔案)
                       'jsapi_ticket_refreshfunc': jsapi ticket 重繪函式 (用于單機及分布式環境下, 具體格式參見檔案)
                       'jsapi_ticket': 直接匯入的 jsapi ticket 值, 該值需要在上一次該類實體化之后手動進行快取并在此處傳入, 如果不
                                       傳入, 將會在需要時自動重新獲取 (傳入 jsapi_ticket_getfunc 和 jsapi_ticket_setfunc 函式
                                       后將會自動忽略此處的傳入值)
                       'jsapi_ticket_expires_at': 直接匯入的 jsapi ticket 的過期日期, 該值需要在上一次該類實體化之后手動進行快取
                                                  并在此處傳入, 如果不傳入, 將會在需要時自動重新獲取 (傳入 jsapi_ticket_getfunc
                                                  和 jsapi_ticket_setfunc 函式后將會自動忽略此處的傳入值)

                       'partnerid': 財付通商戶身份標識, 支付權限專用
                       'partnerkey': 財付通商戶權限密鑰 Key, 支付權限專用
                       'paysignkey': 商戶簽名密鑰 Key, 支付權限專用

                       'checkssl': 是否檢查 SSL, 默認不檢查 (False), 可避免 urllib3 的 InsecurePlatformWarning 警告
        :return:
        """

        self.__request = WechatRequest()

        if kwargs.get('checkssl') is not True:
            disable_urllib3_warning()  # 可解決 InsecurePlatformWarning 警告

        self.__token = kwargs.get('token')

        self.__appid = kwargs.get('appid')
        self.__appsecret = kwargs.get('appsecret')

        self.__encrypt_mode = kwargs.get('encrypt_mode', 'safe')
        self.__encoding_aes_key = kwargs.get('encoding_aes_key')
        self.__crypto = None
        self._update_crypto()

        self.__access_token_getfunc = kwargs.get('access_token_getfunc')
        self.__access_token_setfunc = kwargs.get('access_token_setfunc')
        self.__access_token_refreshfunc = kwargs.get('access_token_refreshfunc')
        self.__access_token = kwargs.get('access_token')
        self.__access_token_expires_at = kwargs.get('access_token_expires_at')

        self.__jsapi_ticket_getfunc = kwargs.get('jsapi_ticket_getfunc')
        self.__jsapi_ticket_setfunc = kwargs.get('jsapi_ticket_setfunc')
        self.__jsapi_ticket_refreshfunc = kwargs.get('jsapi_ticket_refreshfunc')
        self.__jsapi_ticket = kwargs.get('jsapi_ticket')
        self.__jsapi_ticket_expires_at = kwargs.get('jsapi_ticket_expires_at')

        self.__partnerid = kwargs.get('partnerid')
        self.__partnerkey = kwargs.get('partnerkey')
        self.__paysignkey = kwargs.get('paysignkey')

    @property
    def token(self):
        """ 獲取當前 Token """
        self._check_token()
        return self.__token

    @token.setter
    def token(self, token):
        """ 設定當前 Token """
        self.__token = token
        self._update_crypto()  # 改動 Token 需要重新更新 Crypto

    @property
    def appid(self):
        """ 獲取當前 App ID """
        return self.__appid

    @property
    def appsecret(self):
        """ 獲取當前 App Secret """
        return self.__appsecret

    def set_appid_appsecret(self, appid, appsecret):
        """ 設定當前 App ID 及 App Secret"""
        self.__appid = appid
        self.__appsecret = appsecret
        self._update_crypto()  # 改動 App ID 后需要重新更新 Crypto

    @property
    def encoding_aes_key(self):
        """ 獲取當前 EncodingAESKey """
        return self.__encoding_aes_key

    @encoding_aes_key.setter
    def encoding_aes_key(self, encoding_aes_key):
        """ 設定當前 EncodingAESKey """
        self.__encoding_aes_key = encoding_aes_key
        self._update_crypto()  # 改動 EncodingAESKey 需要重新更新 Crypto

    @property
    def encrypt_mode(self):
        return self.__encrypt_mode

    @encrypt_mode.setter
    def encrypt_mode(self, encrypt_mode):
        """ 設定當前加密模式 """
        self.__encrypt_mode = encrypt_mode
        self._update_crypto()

    @property
    def crypto(self):
        """ 獲取當前 Crypto 實體 """
        return self.__crypto

    @property
    def access_token(self):
        """ 獲取當前 access token 值, 本方法會自行維護 access token 有效性 """
        self._check_appid_appsecret()

        if callable(self.__access_token_getfunc):
            self.__access_token, self.__access_token_expires_at = self.__access_token_getfunc()

        if self.__access_token:
            now = time.time()
            if self.__access_token_expires_at - now > 60:
                return self.__access_token

        self.grant_access_token()  # 從騰訊服務器獲取 access token 并更新
        return self.__access_token

    @property
    def jsapi_ticket(self):
        """ 獲取當前 jsapi ticket 值, 本方法會自行維護 jsapi ticket 有效性 """
        self._check_appid_appsecret()

        if callable(self.__jsapi_ticket_getfunc):
            self.__jsapi_ticket, self.__jsapi_ticket_expires_at = self.__jsapi_ticket_getfunc()

        if self.__jsapi_ticket:
            now = time.time()
            if self.__jsapi_ticket_expires_at - now > 60:
                return self.__jsapi_ticket

        self.grant_jsapi_ticket()  # 從騰訊服務器獲取 jsapi ticket 并更新
        return self.__jsapi_ticket

    @property
    def partnerid(self):
        """ 獲取當前財付通商戶身份標識 """
        return self.__partnerid

    @property
    def partnerkey(self):
        """ 獲取當前財付通商戶權限密鑰 Key """
        return self.__partnerkey

    @property
    def paysignkey(self):
        """ 獲取商戶簽名密鑰 Key """
        return self.__paysignkey

    def grant_access_token(self):
        """
        獲取 access token 并更新當前配置
        :return: 回傳的 JSON 資料包 (傳入 access_token_refreshfunc 引數后回傳 None)
        """
        self._check_appid_appsecret()

        if callable(self.__access_token_refreshfunc):
            self.__access_token, self.__access_token_expires_at = self.__access_token_refreshfunc()
            return

        response_json = self.__request.get(
            url="https://api.weixin.qq.com/cgi-bin/token",
            params={
                "grant_type": "client_credential",
                "appid": self.__appid,
                "secret": self.__appsecret,
            },
            access_token=self.__access_token
        )
        self.__access_token = response_json['access_token']
        self.__access_token_expires_at = int(time.time()) + response_json['expires_in']

        if callable(self.__access_token_setfunc):
            self.__access_token_setfunc(self.__access_token, self.__access_token_expires_at)

        return response_json

    def grant_jsapi_ticket(self):
        """
        獲取 jsapi ticket 并更新當前配置
        :return: 回傳的 JSON 資料包 (傳入 jsapi_ticket_refreshfunc 引數后回傳 None)
        """
        self._check_appid_appsecret()

        if callable(self.__jsapi_ticket_refreshfunc):
            self.__jsapi_ticket, self.__jsapi_ticket_expires_at = self.__jsapi_ticket_refreshfunc()
            return

        response_json = self.__request.get(
            url="https://api.weixin.qq.com/cgi-bin/ticket/getticket",
            params={
                "type": "jsapi",
            },
            access_token=self.access_token,
        )
        self.__jsapi_ticket = response_json['ticket']
        self.__jsapi_ticket_expires_at = int(time.time()) + response_json['expires_in']

        if callable(self.__jsapi_ticket_setfunc):
            self.__jsapi_ticket_setfunc(self.__jsapi_ticket, self.__jsapi_ticket_expires_at)

        return response_json

    def get_access_token(self):
        """
        獲取 Access Token 及 Access Token 過期日期, 僅供快取使用, 如果希望得到原生的 Access Token 請求資料請使用 :func:`grant_token`
        **僅為兼容 v0.6.0 以前版本使用, 自行維護 access_token 請使用 access_token_setfunc 和 access_token_getfunc 進行操作**
        :return: dict 物件, key 包括 `access_token` 及 `access_token_expires_at`
        """
        self._check_appid_appsecret()

        return {
            'access_token': self.access_token,
            'access_token_expires_at': self.__access_token_expires_at,
        }

    def get_jsapi_ticket(self):
        """
        獲取 Jsapi Ticket 及 Jsapi Ticket 過期日期, 僅供快取使用, 如果希望得到原生的 Jsapi Ticket 請求資料請使用 :func:`grant_jsapi_ticket`
        **僅為兼容 v0.6.0 以前版本使用, 自行維護 jsapi_ticket 請使用 jsapi_ticket_setfunc 和 jsapi_ticket_getfunc 進行操作**
        :return: dict 物件, key 包括 `jsapi_ticket` 及 `jsapi_ticket_expires_at`
        """
        self._check_appid_appsecret()

        return {
            'jsapi_ticket': self.jsapi_ticket,
            'jsapi_ticket_expires_at': self.__jsapi_ticket_expires_at,
        }

    def _check_token(self):
        """
        檢查 Token 是否存在
        :raises NeedParamError: Token 引數沒有在初始化的時候提供
        """
        if not self.__token:
            raise NeedParamError('Please provide Token parameter in the construction of class.')

    def _check_appid_appsecret(self):
        """
        檢查 AppID 和 AppSecret 是否存在
        :raises NeedParamError: AppID 或 AppSecret 引數沒有在初始化的時候完整提供
        """
        if not self.__appid or not self.__appsecret:
            raise NeedParamError('Please provide app_id and app_secret parameters in the construction of class.')

    def _update_crypto(self):
        """
        根據當前配置內容更新 Crypto 類
        """
        if self.__encrypt_mode in ['compatible', 'safe'] and self.__encoding_aes_key is not None:
            if self.__token is None or self.__appid is None:
                raise NeedParamError('Please provide token and appid parameters in the construction of class.')
            self.__crypto = BasicCrypto(self.__token, self.__encoding_aes_key, self.__appid)
        else:
            self.__crypto = None
示例:

31.飛機大戰游戲

    1.專案目錄結構
        ~/Desktop/Python/03_飛機大戰游戲 $ tree -L 1
        .
        ├── __pycache__
        ├── images
        ├── plane_main.py
        └── plane_sprites.py

    2.plane_main.py檔案代碼

import pygame
from plane_sprites import *


class PlaneGame(object):
    

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/57008.html

標籤:Python

上一篇:10行Python代碼教你如何處理IP地址

下一篇:Python計算大檔案行數方法及性能比較

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more