Python_面向對象

面向對象:類 class 和 對象 object:

01. 什麼是對象:
對象是指現實中的物體或實例python

02. 什麼是面向對象:
把一切當作對象(實例),對象和對象之間用方法(行爲)創建關聯關係
面向過程是一件事怎麼去一步一步實現, 面向對象是一件事有誰(實例)去實現linux

03. 什麼是類:
擁有相同屬性和行爲的對象分爲一組, 即爲一個類
類是用來描述對象的工具web

04. 面向對象示意:
車(類) ----->> BYD E6(京A.88888) 對象(實例)
狗(類) ----->> 小京巴(戶籍號: 00001) 對象(實例)
int(類) ----->> 100(對象,實例)sql

05. 類的建立語法:
class 類名(繼承列表):
"""類文檔字符串"""
實例方法(類內的函數methd) 的定義
類變量(class variable) 定義
類方法(@classmethod)定義
靜態方法(@staticmethod)定義chrome

06. 類的做用:
能夠用類建立一個或多個此類的對象(實例)
類內的變量和方法能被此類所建立的全部實例所共同擁有
說明:
類名必須是標識符(與變量名命名規則相同, 建議首字母大寫)
類名實質上就是變量, 它綁定一個類實例
類的定義最後面要加兩個空格以告訴解釋執行器, 類的定義已經結束
示例:
class Dog:
pass
術語:
類 對象  實例
class object instance數據庫

07. 構造函數:
構造函數的調用表達式: 
  類名([建立傳參列表])
[] 裏的內容表明可省略
做用:
  建立這個類的實例對象, 並返回此實例對象的引用關係
示例:
class Dog: # 定義一個狗類
pass


dog1 = Dog() # 用類來建立一個對象用dog1綁定
print(id(dog1)) # 打印dog1所在的內存地址
dog2 = Dog() # 建立第二個對象 用dog2綁定
print(id(dog2))
print(dog1 is dog2) # 判斷兩隻狗是否是同一條狗, False
實例說明:
實例有本身的做用域或名字空間, 能夠爲該實例添加實例變量(也叫屬性)
實例能夠調用類的方法
實例能夠訪問類中的類變量編程

08. 實例變量(屬性 attribute):
每一個實例能夠有本身的變量, 稱爲實例變量(屬性)
屬性的使用語法:
實例.屬性名
01. 屬性的賦值規則:
(同變量規則相同)
01. 首次爲屬性賦值則建立此屬性
02. 再次爲屬性賦值則改變屬性的綁定關係
示例:
class Dog:
pass


dog1 = Dog()
dog1.kinds = "京巴" #爲dog1綁定的實例添加kinds屬性
dog1.color = "白色" # 添加屬性
print(dog1.kinds, dog1.color) # 訪問屬性
dog1.color = '黃色' # 修改dog1.color 的綁定關係
print(dog1.color)後端

02. 刪除屬性:
del 語句
語法:
del 對象.屬性名
示例:
class Student:
pass
stu = Student()
stu.name = 'xiaozhang' # 建立屬性
print(stu.name)
del stu.name # 刪除此屬性
print(stu.name) # 屬性錯誤,由於屬性已經不存在了
03. 查找順序:
對象.屬性 : 先從對象空間找,若是找不到,再從類空間找,再找不到,再從父類找....
類名.屬性 : 先從本類空間找,若是找不到,再從父類找.... 瀏覽器

09. 實例方法 method:
語法:
class 類名(繼承列表):
def 實例方法名(self, 參數1, 參數2, ....):
語句塊
做用:
用於描述一個對象的行爲,讓此類型的所有對象都擁有相同的行爲
說明:
實例方法的實質是函數, 是定義在類內的函數
實例方法的第一個參數表明調用這個方法的實例, 通常命名爲'self'
實例方法的調用語法:
實例.實例方法名(調用參數)

類名.實例方法名(實例, 調用參數)

初始化方法:
做用:
對新建立的對象添加屬性等必須的資源
語法形式:
class 類名:
# [] 表明其中內容可省略
def __init__(self[, 參數列表]):
語句塊

說明:
初始化方法名必須爲 __init__ 不可改變
初始化方法會在構造函數建立實例後自動調用, 且將實例自身經過第一個參數 self 傳入 __init__ 方法
構造函數的實參將經過 __init__ 方法的參數列表傳到 __init__ 方法中
初始化方法內若是須要 return 語句返回, 則必須返回 None
示例:
# 此示例示意初始化方法的定義方法和調用過程
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)

10. 析構方法:
做用:
在對象被銷燬以前被調用,主要負責清理對象所佔用的資源
語法形式:
class 類名:
def __del__(self):
語句塊
說明:
Python建議儘量少的在析構方法內作事情, 由於銷燬時間難以肯定
示例:
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
while True: # 死循環永遠不退出, del不調用一直不關閉文件
pass
print("程序結束")

11. 預置的實例屬性:
__dict__ 屬性:
用於綁定一個存儲此實例自身變量的字典

__class__ 屬性:
用於綁定建立此實例的類
示例:
class Dog:
pass


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

12. 用於類的函數:
isintance(obj, class_or_tuple)
返回這個對象obj是不是某個類的對象, 或者某些類中的一個類的對象, 若是是則返回True, 不然返回False
type(obj) 返回對象的類
對象:
屬性(對象擁有的名詞) 用實例變量存儲
行爲(對象擁有的動做) 用方法表示

13. 類變量:
類變量是類的屬性, 此屬性屬於類, 不屬於此類建立的實例
說明:
類變量,能夠經過該類直接訪問
類變量能夠經過該類的實例直接訪問
類變量能夠經過此類的對象的 '__class__'屬性間接訪問
示例1:
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 # 間接修改類變量

示例2:
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

14. 類的 __slots__ 屬性:
做用:
限定一個類建立的實例只能有固定的屬性(實例變量)
說明:
__slots__ 屬性是一個列表, 列表的值是字符串
含有 __slots__ 屬性的類所建立的對象沒有__dict__字典
示例:
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__字典

15. 類方法 @classmethod:
類方法是操做類的方法, 類方法屬於類, 不屬於該類建立的對象
說明:
類方法須要使用@classmethod裝飾器定義
類方法的第一個參數用來綁定類, 約定寫爲cls
類和對象實例均可以調用類方法
類方法不能訪問此類建立的對象的屬性
示例:
class A:
v = 0 # 類變量
@classmethod
def get_v(cls): #此方法不是實例方法, 是類方法
return cls.v


a = A()
a.get_v() # 0
A.get_v() # 0
a.__dict__ # {}

16. 靜態方法 @staticmethod:
靜態方法是定義在類的內部的函數, 此函數做用域是類的內部
說明:
靜態方法須要使用@staticmethod裝飾器定義 
靜態方法與普通函數的定義相同, 不須要傳入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

17. 繼承 inheritance 和 派生 derived:
什麼是繼承 / 派生
繼承是從已有類中派生出新類, 新類具備原類的數據屬性和行爲,並能擴展新的能力
派生就是從一個已有的類衍生出新類, 在新的類上添加新的屬性和行爲
做用:
01. 用繼承派生機制, 能夠將一些共有功能加在基類中, 實現代碼的共享
02. 在不改變超類的代碼的基礎上, 改變原有的功能
名詞:
基類(base class) / 超類(super class) / 父類(father class)
派生類(derived class) / 子類(child class)
單繼承:
語法:
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")
繼承說明:
任何類都直接或間接的繼承自object類
object類是一切類的超類

18. 類內的 __base__屬性:
此屬性用來記錄此類的基類
示例:
In [9]: class A:
...: pass
...:

In [10]: class B(A):
...: pass
...:

In [11]: B.__base__
Out[11]: __main__.A

In [12]: A.__base__
Out[12]: object

19. 覆蓋: override:
什麼是覆蓋
覆蓋是指在有繼承派生關係的類中, 子類中實現了與基類(超類)同名的方法
在子類實例調用方法時, 實際調用的是子類中的覆蓋版本, 這種現象叫作覆蓋
示例:
class A:
def work(self):
print("A類的work方法被調用")

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

b = B()
b.work() # 子類已經覆蓋了父類的方法

20. super函數:
super(type, obj) 返回綁定超類的實例(要求obj必須爲type類型的實例)
super() 返回綁定超類的實例, 等同於super(__class__, 實例的第一個參數), 且必須在方法內調用
做用:
  返回超類的實例, 用超類實例來調用其自身的方法
說明:
  當子類實現了__init__方法後, 父類的__init__方法將被覆蓋
即再也不會主動調用父類的__init__方法, 會引發父類的屬性得不到初始化
此時須要顯式調用父類的初始化方法
示例1:
# 此示例示意用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() # 同樣會調用超類的方法
# super(__class__, self).work()

b = B()
b.work() # B類的work方法被調用
print("-----如下用b調用覆蓋版本的方法----")
# A.work(b) # A類的work方法被調用
super(B, b).work()
b.doworks()

示例2:
# 此示例示意顯式調用基類的初始化方法
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()

21. 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

22. 封裝 enclosure:
封裝是指隱藏類的實現細節.讓使用者不關心這些細節;
封裝的目的是讓使用者經過儘量少的使用實例變量名(屬性)操做對象
私有屬性和方法
python類中以雙下劃線('__')開頭, 不以雙下劃線結尾的標識符爲私有成員
私有成員只能被方法調用, 不能在子類或其它地方使用
私有成員有兩種:
私有屬性
私有方法
示例:
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

示例2:
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

23. 多態  polymorphic:
字面意思:多種狀態
多態是指在有繼承/派生關係的類中,調用基類對象的方法,實際能調用子類的覆蓋方法的現象叫多態
多態說明:
多態調用方法與對象相關, 不與類相關
python的所有對象只有"運行時狀態(動態)", 沒有"C++/Java"裏的"編譯時狀態(靜態)"
面向對象編程語言的特徵:
封裝
繼承
多態
面向對象的語言: C++/Java/Python/Swift/C#
示例1:
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) # 正在畫一個點

示例2:
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)

24. 多繼承 multiple inheritance:
多繼承是指一個子類繼承自兩個或兩個以上的基類
語法:
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的速度行駛

多繼承的問題(缺陷)
標識符(名字空間)衝突的問題
要謹慎使用多繼承
示例:
# 小張寫了一個類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方法

25. 多繼承的 MRO (Method Resolution Order)問題:
MRO 方法搜索順序問題
python 3 廣度優先: 一條路走到倒數第二級,判斷,若是其餘路能走到終點,則返回走另外一條路.若是不能,則走到終點.
python 2 深度優先: 一條路走到底.
單獨調用父類的方法示例:
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")

多繼承中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示例:
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")

26. 函數重寫 overwrite:
什麼是函數重寫
在自定義的類中,經過添加特定的方法,讓自定義的類生成的對象(實例) 能象內建對象同樣進行內建函數操做
對象轉字符串函數重寫
repr(obj) 返回一個能表明此對象的字符串,一般:eval(repr(obj)) == obj
str(obj) 經過給定的對象返回一個字符串(這個字符串一般是給人閱讀的)
換句話說:
repr(obj) 返回的字符串是給python用的
str(obj) 返回字符串是給人看的
示例:
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

27. 重寫方法:
repr(obj) 函數的重寫方法 def __repr__(self)
str(obj) 函數的重寫方法 def __str__(self)
當對象沒有 __str__方法時, 則返回__repr__(self)的值

01. 內建函數重寫:
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__()

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

03. 布爾測試函數的重寫:
格式:
def __bool__(self):
pass
做用:
1. 用於bool(obj)函數取值
2. 用於if語句真值表達式中
3. 用於while語句真值表達式中
說明:
布測試式方法的查找順序是 __bool__方法, 其次是__len__方法
若是沒有以上方法則返回True
示例:
# 此示例示意 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')

04. 自定製格式化字符串__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'))

28. 迭代器(高級):
什麼是迭代器
能夠經過 next(obj) 函數取值的對象, 就是迭代器
迭代器協議:
迭代器議是指對象可以使用next函數獲取下一項數據, 在沒有下一項數據時觸發一個StopIteration異常來終止迭代的約定
迭代器協議的實現方法:
在類內須要定義 __next__(self)方法來實現迭代器協議
語法形式:
class MyIterator:
def __next__(self):
迭代器協議
return 數據
什麼是可迭代對象
是指能用iter(obj)函數返回迭代器的對象(實例)
可迭代對象的內部要定義 __iter__(self)方法來返回迭代器對象

29. 屬性管理函數(反射):
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, set(x, 'y', v) 等同於 x.y = v
delattr(obj, name) 刪除對象obj中的name屬性, delattr(x, 'y') 等同於 del x.y
示例1:
# 類反射
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)() # 登陸
示例2:
# 對象放射
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__)
示例3:
# 類反射
class Foo(object):

staticField = "old boy"

def __init__(self):
self.name = 'wupeiqi'

def func(self):
return 'func'

@staticmethod
def bar():
return 'bar'

print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')
示例4:
# 反射當前模塊成員
import sys


def s1():
print 's1'


def s2():
print 's2'


this_module = sys.modules[__name__]

hasattr(this_module, 's1')
getattr(this_module, 's2')
示例5:
# 導入其餘模塊,利用反射查找該模塊是否存在某個方法
def test():
print('from the test')

"""
程序目錄:
module_test.py
index.py

當前文件:
index.py
"""

import module_test as obj

#obj.test()

print(hasattr(obj,'test'))

getattr(obj,'test')()

30. 異常(高級):
with語句
語法:
with 表達式1 [as 變量名1], 表達式2 [as 變量名2], ...
做用:
用於對資源訪問的場合, 確保使用過程當中無論是否發生異常, 都會執行必要有"清理"操做, 並釋放資源.
如:
文件打開後自動關閉, 線程中鎖的自動獲取和釋放
說明:
with語句與try-finally類似, 並不會必變異常狀態
as 子句用於綁定表達式建立的對象
示例:
# 打開文件讀取文件數據(with來實現關閉文件)
def read_file():
try:
# f = open("abcd.txt")
with open('abcd.txt') as f:
while True:
s = f.readline()
if not s:
break # return
int(input("請輸入任意數字打印下一行:"))
print(s)
print("文件已經關閉")

except IOError:
print("出現異常已經捕獲!")
except ValueError:
print("程序已轉爲正常狀態")


read_file()
print("程序結束")

31. 環境管理器(上下文管理器):
1. 類內有__enter__ 和 __exit__方法的類被稱爲環境管理器
2. 可以用with進行管理的對象必須是環境管理器
3. __enter__ 將在進入with語句時被調用, 並返回由as變量管理的對象
4. __exit__ 將在離開with語句時被調用, 且能夠用參數來判斷離開with語句時是否出現異常並作出相應的處理
示例:
# 本程序示意自定義的類做爲環境管理器使用
class FileWriter:
def __init__(self, filename):
self.filename = filename # 此屬性用於記住文件名

def writeline(self, s):
'''此方法用於向文件內寫入字符串,同時自動添加換行'''
self.file.write(s)
self.file.write('\n')

def __enter__(self):
'''此方法用於實現環境管理器'''
self.file = open(self.filename, 'w')
print("已進入__enter__方法,文件打開成功")
return self # 返回值向用於 with中的as 綁定

def __exit__(self, exec_type, exec_value, exec_tb):
'''
exec_type 爲異常類異,沒有異常發生時爲None
exec_value 爲錯誤的對象,沒有異常時爲None
exec_tb 爲錯誤的traceback對象
'''
self.file.close()
print("文件", self.filename, "已經關閉")
if exec_type is None:
print("退出with時沒有發生異常")
else:
print("退出with時,有異常,類型是", exec_type,
"錯誤是", exec_value)
print("__exit__法被調用,已離開with語句")


try:
with FileWriter('log.txt') as fw:
while True:
s = input("請輸入一行: ")
if s == 'exit':
break
if s == 'error':
raise ValueError("故意製造的值錯誤")
fw.writeline(s)
except:
print("有錯誤發生,已轉爲正常")

print("這是with語句以外,也是程序的最後一條語句")

32. 運算符重載:
什麼是運算符重載
讓自定義的類生成的對象(實例)可以使用運算符進行操做
做用:
讓實例象數學表達式同樣進行運算操做
讓程序簡潔易讀
說明:
運算符重載方法的參數已經有固定的含義, 不建議改變原有的含義

01. 算術運算符:
方法名 運算符
__add__ 加法 +
__sub__ 減法 -
__mul__ 乘法 *
__truediv__ 除法 /
__floordiv__ 地板除 //
__mod__ 取模(求餘) %
__pow__ 冪 **
二元運算符重載方法格式:
def __xxx__(self, other):
....
示例:
# 此程序示意運算符重載
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)

02. 反向算術運算符:
方法名 運算符
__radd__ 加法 +
__rsub__ 減法 -
__rmul__ 乘法 *
__rtruediv__ 除法 /
__rfloordiv__ 地板除 //
__rmod__ 取模(求餘) %
__rpow__ 冪 **
示例:
# 此示例示意返向算術運算符的重載
class MyList:
def __init__(self, iterable):
self.data = [x for x in iterable]

def __repr__(self):
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 # 實現乘法運算
print('L4 =', L4) # MyList([1,2,3,1,2,3])
L5 = 2 * L1
print(L5)

03. 複合賦值運算符重載:
方法名 運算符
__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))
L1 += L2 # 至關於 L1 = L1 + L2
print('L1 =', L1)
print("id(L1) =", id(L1))
問題:
# 解法1
a = [100]
def test(x):
x = x + x
print(x)

test(a) # [100, 100]
print(a) # [100]

# 解法2
a = [100]
def test(x):
x += x # 此處與上題不一樣。結果也會不一樣
print(x)

test(a) # [100, 100]
print(a) # [100, 100]

04. 比較的運算符的重載:
__lt__ < 小於
__le__ <= 小於等於
__gt__ > 大於
__ge__ >= 大於等於
__eq__ == 等於
__ne__ != 不等於
注:
比較運算符一般返回True或False

05. 位運算符重載:
__inert__ ~ 取反(一元運算符)
__and__ & 位與(交集)
__or__ | 位或(並集)
__xor__ ^ 位異或(對稱補集)
__lshift__ << 左移
__rshift__ >> 右移

06. 反向位運算符重載:
同算術運算符相同
__rand__ & 位與(交集)
__ror__ | 位或(並集)
__rxor__ ^ 位異或(對稱補集)
__rlshift__ << 左移
__rrshift__ >> 右移

07. 複合賦值運算符重載:
__iand__ &= 位與(交集)
__ior__ |= 位或(並集)
__ixor__ ^= 位異或(對稱補集)
__ilshift__ <<= 左移
__irshift__ >>= 右移

08. 一元運算符的重載:
__neg__ - 負號
__pos__ + 正號
__invert__ ~ 按位取反
格式:
def __xxx__(self):
....
示例:
# 此示例示意一元運算符的重載
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)

09. in / not in 運算符的重載:
格式:
def __contains__(self, e): # e表明元素
...
說明:
not in 至關於 in取反, 全部只須要重載in 便可
# 此示例示意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)
return self.data[i]

def __setitem__(self, i, v):
self.data[i] = v

L1 = MyList([1, -2, 3, -4, 5])
print(L[0:2]) # [1, -2]
print(L1[2]) # 3
L1[1] = 2
print(L1) # MyList([1, 2, 3, -4, 5])

33. 組合:
給一個類的對象封裝一個屬性,這個屬性是另外一個類的對象
示例1:
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,%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)

示例2:
# 組合實現與類的關聯
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))

34. 接口類, 抽象類:
定製一個規範, 讓其子類必須按照此規範實現
示例:
from abc import ABCMeta, abstractmethod


class Payment(metaclass=ABCMeta): # 抽象類(接口類):
@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()


w1 = Wechatpay(200)
a1 = Alipay(200)
j1 = Jdpay(100)
pay(a1) # 歸一化設計
pay(j1)

35. 靜態屬性:
將方法假裝成一個屬性,代碼上沒有什麼提高,只是更合理
語法:
@property
@屬性名.setter
@屬性名.deleter
示例1:
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取代getter和setter方法
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)

36. 單例:
若是一個類 從頭至尾只能有一個實例,說明從頭至尾之開闢了一起屬於對象的空間,那麼這個類就是一個單例類
示例1:
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)
s2 = Single('gogo',40)

示例2:
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>

37. __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)

01.開闢一個空間,屬於對象的
02.把對象的空間傳給self,執行init
03.將這個對象的空間返回給調用者
obj = Single()
single的new,single沒有,只能調用object的new方法
new方法在實例化以後,__init__ 以前先執行new來建立一塊空間

38. __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()
a() # 對象() == 至關於調用__call__方法
a.call()

A()() # 類名()() ,至關於先實例化獲得一個對象,再對對象(),==>和上面的結果同樣,至關於調用__call__方法
B(A)

39. item 系列方法:
item系列 和對象使用[]訪問值有聯繫
示例1:
obj = {'k':'v'}
print(obj) # 字典的對象
print(obj['k'])

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)
b['k1'] = 'v1' # __setitem__
print(b['k1']) # __getitem__
del b['k1'] # __delitem__
print(b['k1'])

示例2:
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'}

40. __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)
print(aa3 == aa == aa4) # ==這個語法 是徹底和__eq__

41. 面向對象設計:
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"])

# 面向對象編程-->用面向對象獨有的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'>

42. 靜態屬性, 類方法, 靜態方法:
@property @classmethod @staticmethod
綜合示例:
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")

43. 包裝標準類型:
基於標準數據類型來定製咱們本身的數據類型,新增/改寫方法
# 包裝=繼承+派生
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))
print("列表%s的中間值是%s" %(l1, l1.show_midlle()))
l1.append("coco")
l1.append(123)
print(l1)

44. 重寫反射方法:
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__)

45. 受權:
受權是包裝的一個特性, 包裝一個類型一般是對已存在的類型的一些定製,這種作法能夠新建,修改或刪除原有產品的功能,其它的則保持原樣。
受權的過程,便是全部更新的功能都是由新類的某部分來處理,但已存在的功能就受權給對象的默認屬性
實現受權的關鍵點就是覆蓋__getattr__方法
示例1:
# 受權-->是組合的運用
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)
print(f1.reads)
print(f1.read)
f1.write("hello world\n")
f1.seek(0) # 移動文件指針到文件開頭
print("讀文件%s內容是%s" % (f1.filename, f1.read()))

示例2:
#加上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)
f1.close()

示例3:
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)
l.append(4)
print(l)
# l.append('3333333') #報錯,必須爲int類型

print(l.mid)

#基於受權,得到insert方法
l.insert(0,-123)
print(l)

46. 雙下方法其它補充, 示例說明:
示例1:
# isinstance(obj,cls)檢查是否obj是不是類 cls 的對象
class Foo():
def __getattr__(self, item):
print("執行了getattr查找%s" % item)

# 不管是否找到屬性都會執行getattribute
def __getattribute__(self, item):
print("執行了getattribute查找%s" % item)
raise AttributeError("拋出異常")


f1 = Foo()
print(isinstance(f1, Foo)) # 判斷對象是不是類實例化出來的 True

# issubclass(sub, super)檢查sub類是不是 super 類的派生類
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)


print(issubclass(Bar, Foo)) # 判斷子類是不是由父類繼承來的 True
f1.x # 執行了 __getattribute__ 查找x -->執行了 __getattr__ 查找x
f2 = Bar()
f2["name"] = "coco"
print(f2["name"])
f2["age"] = "18"
print(f2.__dict__)
del f2["age"]
print(f2.__dict__)

示例2:
# __str__ 與 __repr__ 示例
class Foo1():
# 運用在print打印時觸發
def __str__(self):
return "自定義打印信息"

# 運用在解釋器時觸發
def __repr__(self):
return "自定義打印信息2"


l2 = Foo1()
print(l2) # 自定義打印信息
print(l2) # 自定義打印信息,__str__和 __repr__共存,print先找str沒有再找repr

示例3:
# __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

示例4:
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'>

# __del__析構函數,回收實例時觸發
f3 = Foo3()

f3() # __call__方法讓實例對象能夠加()執行

示例5:
# 描述符__get__ __set__ __delete__
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

示例6:
# 上下文管理器 實現 __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("結束") # 結束

示例7:
# __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))

示例8:
# __len__
class B:
def __len__(self):
print(666)

b = B()
len(b) # len 一個對象就會觸發 __len__方法。

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

def __len__(self):
return len(self.__dict__)
a = A()
print(len(a))

示例9:
# __iter__
用於迭代器,之因此列表、字典、元組能夠進行for循環,是由於類型內部定義了 __iter__
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

示例10:
分片操做 __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__

47. 描述符的應用與優先級:
描述符本質就是一個新式類,在這個新式類中,至少實現了__get__(),__set__(),__delete__()中的一個,這也被稱爲描述符協議
__get__():調用一個屬性時,觸發
__set__():爲一個屬性賦值時,觸發
__delete__():採用del刪除屬性時,觸發
數據描述符:至少實現了__get__()和__set__()
非數據描述符:沒有實現:__set__()
描述符應用示例:
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__)

描述符的優先級:
類屬性 > 數據描述符 > 實例屬性 > 非數據描述符 > 找不到的屬性觸發__getattr__()

01. 類屬性 > 數據描述符:
#描述符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


# 在一個類中定義描述符它就是一個類屬性,存在於類的屬性字典中,而不是實例的屬性字典
# 描述符被定義成了一個類屬性,直接經過類名也能夠調用
People.name #調用類屬性name,本質就是在調用描述符Str,觸發了__get__()

People.name='coco' # 賦值並無觸發__set__()
del People.name # del也沒有觸發__delete__()
'''
緣由:描述符在使用時被定義成另一個類的類屬性,於是類屬性比二次加工的描述符假裝而來的類屬性有更高的優先級
People.name # 調用類屬性name,找不到就去找描述符假裝的類屬性name,觸發了__get__()
People.name='coco' # 直接賦值了一個類屬性,它擁有更高的優先級,至關於覆蓋了描述符,不會觸發描述符的__set__()
del People.name #同上
'''

02. 數據描述符 > 實例屬性:
#描述符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)

# 若是描述符是一個數據描述符(即有__get__又有__set__),那麼p1.name的調用與賦值都是觸發描述符的操做,於p1自己無關了,至關於覆蓋了實例的屬性
p1.name='coco'
p1.name
print(p1.__dict__) # 實例的屬性字典中沒有name,由於name是一個數據描述符,優先級高於實例屬性,查看/賦值/刪除都是跟描述符有關,與實例無關了
del p1.name

03. 實例屬性 > 非數據描述符:
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)
r1.name
r1.name='廚房'

 

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='廚房'

04. 非數據描述符 > 找不到:
class Foo:
def func(self):
print('func被調用')

def __getattr__(self, item):
print('找不到就調用getattr',item)
f1=Foo()

f1.xxx # 找不到就調用getattr xxx

48. 類裝飾器應用:
01. 類的裝飾器無參數示例:
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,3333.3)

02. 類的裝飾器有參數示例:
示例1:
def typeassert(**kwargs):
def decorate(cls):
print('類的裝飾器開始運行啦------>',kwargs)
return cls
return decorate
@typeassert(name=str,age=int,salary=float) #有參:1.運行typeassert(...)返回結果是decorate,此時參數都傳給kwargs 2.People=decorate(People)
class People:
def __init__(self,name,age,salary):
self.name=name
self.age=age
self.salary=salary

p1=People('egon',18,3333.3)

示例2:
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指向的函數
#2. test指向了用Test建立出來的實例對象
#3. 當在使用test()進行調用時,就至關於讓這個對象(),所以會調用這個對象的__call__方法
#4. 爲了可以在__call__方法中調用原來test指向的函數體,因此在__init__方法中就須要一個實例屬性來保存這個函數體的引用
# 因此纔有了self.__func = func這句代碼,從而在調用__call__方法中可以調用到test以前的函數體
@Test
def test():
print("----test---")
test()
showpy()#若是把這句話註釋,從新運行程序,依然會看到"--初始化--"

03. 描述符裝飾器綜合運用示例:
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__)

49. 用描述符定製 @property, @classmethod, @staticmethod:
01. 定製@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>

02. 定製@classmethod:
class ClassMethod:
def __init__(self,func):
self.func=func

def __get__(self, instance, owner): #類來調用,instance爲None,owner爲類自己,實例來調用,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

def __get__(self, instance, owner): #類來調用,instance爲None,owner爲類自己,實例來調用,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('天天都是充滿但願的一天')

03. 定製@staticmethod:
class StaticMethod:
def __init__(self,func):
self.func=func

def __get__(self, instance, owner): #類來調用,instance爲None,owner爲類自己,實例來調用,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)

50. 自定義元類:
元類就是用來建立這些類(對象)的,元類就是類的類, type就是Python在背後用來建立全部類的元類
做用: 攔截類的建立, 修改類, 返回修改以後的類
類中有一個屬性 __metaclass__,其用來表示該類由 誰 來實例化建立,因此,咱們能夠爲 __metaclass__ 設置一個type類的派生類,從而查看 類 建立的過程
示例1:
class MyType(type):
def __init__(self, a, b, c):
print(a) # Foo
print(b) # ()
print(c) # {'__module__': '__main__', '__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x00000000056307B8>}
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(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}

示例2:
class MyType(type):
def __init__(self, what, bases=None, dict=None):
super(MyType, self).__init__(what, bases, dict)

def __call__(self, *args, **kwargs):
obj = self.__new__(self, *args, **kwargs)

self.__init__(obj)

class Foo(object):
__metaclass__ = MyType

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

def __new__(cls, *args, **kwargs):
return object.__new__(cls, *args, **kwargs)

# 第一階段:解釋器從上到下執行代碼建立Foo類
# 第二階段:經過Foo類建立obj對象
obj = Foo()

示例3:
class UpperAttrMetaClass(type):
# __new__ 是在__init__以前被調用的特殊方法
# __new__是用來建立對象並返回之的方法
# 而__init__只是用來將傳入的參數初始化給對象
# 你不多用到__new__,除非你但願可以控制對象的建立
# 這裏,建立的對象是類,咱們但願可以自定義它,因此咱們這裏改寫__new__
# 若是你但願的話,你也能夠在__init__中作些事情
# 還有一些高級的用法會涉及到改寫__call__特殊方法,可是咱們這裏不用
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'

51. 元類實現ORM:
ORM釋義:
ORM 是 python編程語言後端web框架 Django的核心思想,「Object Relational Mapping」,即對象-關係映射,簡稱ORM
建立一個實例對象,用建立它的類名當作數據表名,用建立它的類屬性對應數據表的字段,當對這個實例對象操做時,可以對應MySQL語句
做用:
ORM就是讓開發者在操做數據庫的時候,可以像操做對象時經過xxxx.屬性=yyyy同樣簡單
示例1:
# 經過元類簡單實現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 User(metaclass=ModelMetaclass):
uid = ('uid', "int unsigned")
name = ('username', "varchar(30)")
email = ('email', "varchar(30)")
password = ('password', "varchar(30)")
# 當指定元類以後,以上的類屬性將不在類中,而是在__mappings__屬性指定的字典中存儲
# 以上User類中有
# __mappings__ = {
# "uid": ('uid', "int unsigned")
# "name": ('username', "varchar(30)")
# "email": ('email', "varchar(30)")
# "password": ('password', "varchar(30)")
# }
# __table__ = "User"
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)


u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
# print(u.__dict__)
u.save()

示例2:
# 抽取到基類中
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)")

u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd') # print(u.__dict__) u.save()

相關文章
相關標籤/搜索