1 面向?qū)ο?/h2>
面向過程是一件事“該怎么做”,面向?qū)ο笫且患?/span>“該讓誰來做”,那個(gè)“誰”就是對(duì)象,他要怎么做是他自己的事,反正最后一群對(duì)象合力能把事做好。
類和對(duì)象
對(duì)象是面向?qū)ο蟮暮诵,在使用?duì)象的過程中,為了將具有共同特征和行為的一組對(duì)象抽象定義,提出另外一個(gè)新的概念——類
1) 類就相當(dāng)于制造飛機(jī)時(shí)的圖紙,用它來進(jìn)行創(chuàng)建的飛機(jī)就相當(dāng)于對(duì)象
2) 類就是創(chuàng)建對(duì)象的模板
3) 一切皆對(duì)象
面向?qū)ο蟮娜齻(gè)特性:繼承、封裝、多態(tài)。
類的構(gòu)成,(分為3部分):
1) 類的名稱:類名
2) 類的屬性:一組數(shù)據(jù),顏色、大小、高矮,年齡。。
3) 類的方法:允許對(duì)進(jìn)行操作的方法(行為)
定義類
定義一個(gè)類,格式如下:
class 類名:
方法列表
創(chuàng)建對(duì)象
創(chuàng)建對(duì)象的格式為:
對(duì)象名=類名()
self的說明
在類的方法中,第一個(gè)參數(shù)一定是self,表示調(diào)用這個(gè)方法的對(duì)象本身
例,定義一個(gè)類和對(duì)象
#定義一個(gè)類
class Car:
def start(self): #方法的參數(shù)一定是self,否則報(bào)錯(cuò)
print("汽車啟動(dòng)")
def print_car_info(self):
print("車的名字:%s,顏色為:%s"%(self.name,self.color))
#當(dāng)創(chuàng)建一個(gè)對(duì)象時(shí),就是一個(gè)模子來制造一個(gè)實(shí)物
autoHome=Car() #構(gòu)建一個(gè)Car的實(shí)例對(duì)象,一定在內(nèi)存中有一塊空間存放對(duì)象的數(shù)據(jù)信息,此時(shí)可以通過實(shí)例對(duì)象autoHome來訪問屬性或者方法,
# autoHome是一個(gè)對(duì)象,它擁有屬性(數(shù)據(jù))和方法(函數(shù))
autoHome.name='邁騰' #給對(duì)象添加屬性,再次出現(xiàn) autoHome.name='XXXX'表示對(duì)屬性進(jìn)行修改
autoHome.color='金色'#'邁騰’,'金色'。。。等數(shù)據(jù)集中到對(duì)象autoHome里面就是對(duì)象autoHome的封裝
BWM=Car() #構(gòu)建另外一個(gè)對(duì)象,與autoHome不同,但同屬于一個(gè)類
autoHome.print_car_info() #調(diào)用對(duì)象的方法print_car_info()
autoHome.start() #調(diào)用對(duì)象的方法start(),這里start()里面的self代表autoHome
BWM.start() # 這里start()里面的self代表對(duì)象BWM
魔法方法__init__
1. __init__()方法,在創(chuàng)建一個(gè)對(duì)象時(shí)默認(rèn)被調(diào)用,不需要手動(dòng)調(diào)用
2. __init__(self)中,默認(rèn)有1個(gè)參數(shù)名稱為self,如果在創(chuàng)建對(duì)象時(shí)傳遞了2個(gè)實(shí)參,那么__init__(self)中除了self作為第一個(gè)形參外,還需要2個(gè)形參,例__init__(self,x,y)
3. __init__(self)中的self參數(shù),不需要開發(fā)者傳遞,python解釋器會(huì)自動(dòng)把當(dāng)前 的對(duì)象引用傳遞進(jìn)去。
例
'''
class Person:
def __init__(self): #初始化對(duì)象的方法,不是構(gòu)建對(duì)象的方法,python解釋器自動(dòng)調(diào)用
print("對(duì)象初始化")
self.name = 'zs'
self.age = '18'
def work(self):
pass
p1 = Person() #自動(dòng)調(diào)用 __init__()方法
print(p1.name)
'''
class Person():
def __init__(self, name, age, height): #初始化對(duì)象的方法,不是構(gòu)建對(duì)象的方法,python解釋器自動(dòng)調(diào)用
self.name = name #self.name 指的是對(duì)象屬性為name,后面的name指的是參數(shù)name
self.age = age
self.height = height
def __str__(self): #把對(duì)象轉(zhuǎn)換成字符串,還不是地址,必須要有返回值
return "姓名:%s,年齡:%s,身高:%s"%(self.name, self.age, self.height)
def introduce(self):
print("姓名:%s,年齡:%s,身高:%s"%(self.name, self.age, self.height))
p1 = Person('zs', 18, 175) #自動(dòng)調(diào)用 __init__()方法
#p1.introduce()
print(p1)
小結(jié):
1. 在Pyth中方法名如果 是__XXXX__()的,那么就有特殊的功能,因此叫做“魔法”方法
2. 當(dāng)使用print輸出對(duì)象的時(shí)候,只要自己定義了__str__(self)方法,那么就會(huì)打印從在這個(gè)方法中return的數(shù)據(jù),必須要有返回值
保護(hù)對(duì)象的屬性
如果有一個(gè)對(duì)象,當(dāng)需要對(duì)其進(jìn)行修改屬性時(shí),有2種方法
l 對(duì)象名.屬性名=數(shù)據(jù) #直接修改
l 對(duì)象名.方法名() #間接修改
為了更好的保存屬性的安全,即不能隨意修改,一般的處理方式為:
l 將屬性定義為私有屬性(或稱為隱藏屬性)
l 添加一個(gè)可以調(diào)用的方法,供調(diào)用
【小結(jié)】:
python中沒有像C++中private這些關(guān)鍵字來區(qū)別公有屬性和私有屬性,
python以屬性命名方式來區(qū)分,如果在屬性名前面加了2個(gè)下劃線’__’,則表示該屬性為私有屬性,否則為公有屬性(方法也是一樣,方法名前面加2個(gè)下劃線的話,表示該方法是私有的,否則為公有)
xx | 公有變量 |
|
_x | 單前置下劃線 | 私有化屬性或方法,不能導(dǎo)入到其他py文件 |
__xx | 雙前置下劃線 | 避免與子類中的屬性命名沖突,無法在外部直接訪問(名字重整所以訪問不到) |
__xx__ | 雙前后下劃線 | 用戶名字空間的魔法對(duì)象或?qū)傩。例?/span>__init__,不要自己發(fā)明這樣的名字__ |
xx_ | 單后置下劃線 | 用于避免與python關(guān)鍵詞的沖突 |
class User:
def __init__(self,pw):
if len(pw)>=6:
self.__password = pw #隱藏(私有)屬性,不允許外部代碼調(diào)用和修改
else:
print("密碼%s不符合規(guī)則"%pw)
def __str__(self):
return "密碼%s"%self.__password
def get_password(self):
return self.__password
self.__say_hello() #內(nèi)部可以調(diào)用隱藏方法
def __say_hello(self): #隱藏方法不允許外問題代碼調(diào)用
print(self.__password)
u1 = User('1231123')
print(u1)
#u1.__say_hello() # 隱藏方法,外部代碼無法進(jìn)行修改
#u1.__password='1234123' # 隱藏屬性,外部代碼無法進(jìn)行修改
print(u1.get_password()) # 需要通過對(duì)象的方法調(diào)用隱藏屬性
私有屬性:通過name mangling(名字重整)目的就是以防子類意外重寫基類的方法或者屬性。
_Class_object機(jī)制就可以訪問private


property用法
為私有屬性添加getter和setter方法

使用property升級(jí)getter和setter方法
例:money=property(getMoney,setMoney)

使用property取代getter和setter方法(注意:方法名與私有屬性名字保持一致)。
方法名前加修飾器@property,該方法變?yōu)?/span>getter
@property
@money.setter

__del__()方法
創(chuàng)建對(duì)象后,python解釋器默認(rèn)用戶__init__()方法,
當(dāng)刪除一個(gè)對(duì)象時(shí),python解釋器也會(huì)默認(rèn)調(diào)用一個(gè)方法,這個(gè)方法為__del__()方法,
當(dāng)內(nèi)存中構(gòu)建 一個(gè)對(duì)象數(shù)據(jù)時(shí),回調(diào)__init__()方法
當(dāng)內(nèi)存中銷毀(釋放)一個(gè)對(duì)象時(shí),回調(diào)__del__()方法
class User:
def __init__(self):
print("******對(duì)象初始化*****")
def __del__(self):
print("******對(duì)象即將要被銷毀******")
u1 = User() # 新建一個(gè)對(duì)象
u2 = u1 # 將u1 賦值u2 ,共同指向一個(gè)對(duì)象
del u1 # 刪除 u1 與對(duì)象的引用關(guān)系
print("--"*30)
#del u2 # 刪除 u2 與對(duì)象的引用關(guān)系,對(duì)象未被引用(或程序結(jié)束時(shí)),被回收
print("=="*30)
Ø 當(dāng)有1個(gè)變量保存了對(duì)象的引用時(shí),此對(duì)象的引用計(jì)數(shù)就會(huì)加1
Ø 當(dāng)使用DEL刪除變量指向的對(duì)象時(shí),如果對(duì)象的引用計(jì)數(shù)不是1,比如3,那么此時(shí)只會(huì)讓這個(gè)引用計(jì)數(shù)減1,即變?yōu)?/span>2,當(dāng)再次調(diào)用DEL時(shí),變?yōu)?/span>1,如果 再調(diào)用1次DEL,此時(shí)會(huì)真的把對(duì)象進(jìn)行刪除
繼承(單繼承)
繼承,在程序中,繼承描述的是事物之間的所屬關(guān)系,如貓狗都屬于動(dòng)物,程序中便可以描述為貓和狗繼承自動(dòng)物;同理,波斯貓和巴厘貓都繼承自貓,而沙皮狗和斑點(diǎn)狗都繼承狗。
只繼承父類的公有方法
class Animal:
def __init__(self):
print("***動(dòng)物的初始化***")
self.name='動(dòng)物'
def eat(self,food):
print("***吃飯***%s" %food)
def sleep(self):
print("***睡覺***")
class Dog(Animal): # 繼承父類(Animal)的方法
def __init__(self, name): # 初始化,屬性name
self.name = name
def shout(self):
print("***旺旺***")
class Cat(Animal): # 繼承父類(Animal)的方法
#def __init__(self): #未定義初始化方法時(shí),調(diào)用父類的__init__()方法,
# print("貓初始化了")
def catch(self):
print("----捉老鼠----")
dog = Dog("小白") #傳遞數(shù)據(jù)給屬性
dog.eat("骨頭") # 調(diào)用父類的方法
dog.shout()
print(dog.name)
cat = Cat()
print(cat.name)
多繼承
class A:
def test(self):
print("A****test()")
class B:
def test(self):
print("B****test()")
class C(A,B):# C繼承了父類A和B
def test(self):
print("C****test()")
c = C()
print(C.__mro__) #查看方法優(yōu)先級(jí)
c.test()
輸出:
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>) 'object'是所有類的父類
C****test()
重寫父類方法與調(diào)用父類方法
1. 重寫父類方法
所謂重寫,就是子類中,有一個(gè)和父類相同名字的方法,在子類中的方法會(huì)覆蓋掉父類中同名的方法
class Animal:
def __init__(self):
print("***動(dòng)物的初始化***")
self.color = '黃色'
def eat(self):
print("***Animal類的eat方法" )
def sleep(self):
print("***睡覺***")
class Dog(Animal): # 繼承父類(Animal)的方法
def __init__(self, name): # init和父類的init名字一樣,所以叫方法的重寫
self.name = name
super().__init__() # super().父類方法名稱,主調(diào)用父類的init方法
def eat(self):
super().eat()
print("**DOG自己的eat方法")
def shout(self):
print("***旺旺***")
dog = Dog("小白")
print(dog.name, dog.color)
dog.eat()
輸出:
***動(dòng)物的初始化***
小白 黃色
***Animal類的eat方法
**DOG自己的eat方法
多態(tài)
多態(tài)的概念是應(yīng)用于java和C#這一類強(qiáng)類型語言中,而python崇尚鴨子類型。
所謂多態(tài),定義時(shí)的類型和運(yùn)行時(shí)的類型不一樣,此時(shí)就稱為多態(tài)。
類屬性
類屬性就是類對(duì)象所擁有的屬性,它被所有類對(duì)象的實(shí)例對(duì)象所共有,在內(nèi)存中只存在一個(gè)副本,這個(gè)和C++中類的靜態(tài)成員變量有點(diǎn)類似。對(duì)于公有的類屬性,在類外可以通過類對(duì)象和實(shí)例對(duì)象訪問。
類屬性:所屬類的,這個(gè)類下的所有對(duì)象都可以共享這個(gè)類屬性。相當(dāng)于JAVA中靜態(tài)屬性,可以被子類繼承
class User(object):
name = 'ZhangSan' #類屬性,公有
__password = '123456' #類屬性,私有(隱藏的)
def __init__(self, sex, username):
self.sex = sex #對(duì)象屬性
self.username = username #對(duì)象屬性
u = User("男",'goldbin')
print("u名稱:%s"%u.name)#當(dāng)對(duì)象屬性與類屬性名字一樣,如果通過對(duì)象來訪問,會(huì)選擇對(duì)象屬性,通過類訪問會(huì)選擇類屬性
u2 = User("女", "adsf")
print("u2名稱:%s"%u2.name)
u.name = 'ww' #本質(zhì)沒有修改類的屬性,僅僅給該對(duì)象定義了一個(gè)對(duì)象屬性name,并賦值為'ww'
print(u.name)
User.name = 'ww' #真正的類屬性的修改,通過類的名稱來修改
print(User.name)
# 對(duì)象屬性,對(duì)象不一樣,屬性不一樣
# 類屬性,所有對(duì)象共有同一個(gè)類屬性
輸出:
u名稱:ZhangSan
u2名稱:ZhangSan
【小結(jié)】
如果需要在類外修改類屬性,必須通過類對(duì)象去引用然后進(jìn)行修改。如果通過實(shí)例對(duì)象去引用,會(huì)產(chǎn)生一個(gè)同名的實(shí)例屬性,這種方式修改的是實(shí)例屬性,不會(huì)影響到類屬性,并且之后如果 通過實(shí)例對(duì)象去引用該名稱的屬性,實(shí)例屬性會(huì)強(qiáng)制屏蔽掉類屬性,即引用的是實(shí)例屬性,除非刪除了該實(shí)例屬性
屬性叫法 | 變量叫法 | 描述 |
類屬性(私有和公有) | 類變量 | 所有對(duì)象共享同一份類屬性 |
實(shí)例屬性(私有和公有) | 成員變量 | 每個(gè)不同對(duì)象,有不一樣值的實(shí)例屬性 |
類方法
類方法是類對(duì)象所擁有的方法,需要用修飾器@classmethod來標(biāo)識(shí) 其為類方法,對(duì)于類方法,第一個(gè)參數(shù)必須 是類對(duì)象,一般以cls作為第一個(gè)參數(shù)(當(dāng)然可以用其他名稱的變量作為其第一個(gè)參數(shù),但是大部分人都習(xí)慣以‘cls’作為第一個(gè)參數(shù)的名字,就最好用cls),能夠通過實(shí)例對(duì)象和類對(duì)象去訪問
class A(object):
name = 'Zhangsan'
def test1(self):
print("A的test1方法")
# 類方法一定要在方法的上面加上一個(gè)修飾器(java注解)
# 類方法的參數(shù)一定是cls,代表當(dāng)前的類
@classmethod
def test2(cls): #cls代表當(dāng)前類
cls.name = 'WangWu'#cls類對(duì)象直接修改類屬性
print("A的test2方法")
a = A()
a.test1()
a.test2()# 通過實(shí)例對(duì)象訪問類方法
A.test2() # 可以直接用類名調(diào)用類方法
print(A.name)
【小結(jié)】
從類方法和實(shí)例方法以及靜態(tài)方法的定義形式就可以看出來,類方法的第一個(gè)參數(shù)是類對(duì)象cls,那么通過cls引用的必定是類對(duì)象的屬性和方法;而實(shí)例方法的第一個(gè)參數(shù)是實(shí)例對(duì)象self,那么通過self引用的可能是類屬性,也有可能 是實(shí)例屬性(這個(gè)需要具體分析),不過在存在相同名稱的類屬性和實(shí)例屬性的情況下,實(shí)例屬性優(yōu)先級(jí)更高。靜態(tài)方法中不需要額外定義參數(shù),因此在靜態(tài)方法中引用類屬性的話,必須 通過類對(duì)象來引用。
方法類別 | 語法 | 描述 |
類方法 | @classmethod | 第一個(gè)形參cls,默認(rèn)傳遞 |
靜態(tài)方法 | @staticmethod | 沒有默認(rèn)傳遞的形參 |
對(duì)象方法(成員方法) | def 方法名 | 第一個(gè)形參是self,默認(rèn)傳輸 |
靜態(tài)方法
需要通過修飾器@staticmethod來進(jìn)行修飾,靜態(tài)方法不需要多定義參數(shù)
class A(object):
name = 'Zhangsan'
@staticmethod # 靜態(tài)方法,屬于類,沒有默認(rèn)傳遞的參數(shù),可以通過類的對(duì)象和類名調(diào)用
def test3():
A.name = 'LiSi' # 通過類名稱訪問類屬性
print("A的test3靜態(tài)方法")
a = A()
a.test3()
A.test3()
print(A.name)
__new__()方法
__new__,對(duì)象構(gòu)造時(shí)由python調(diào)用的方法,必須有返回值,返回當(dāng)前類的對(duì)象。
Ø __new__與__init__不同時(shí),new方法用于構(gòu)建對(duì)象,init用于初始化對(duì)象,默認(rèn)調(diào)用父類object的方法。
Ø __new__至少要有一個(gè)參數(shù)cls,代表要實(shí)例化的類,此參數(shù)在實(shí)例化時(shí)由python解釋器自動(dòng)提供
Ø __new__必須要有返回值,返回實(shí)例化出來的實(shí)例,這點(diǎn)在自己實(shí)現(xiàn)__new__時(shí)要特別注意,可以return父類__new__出來的實(shí)例,或者直接是object的__new__出來的實(shí)例
Ø __init__有一個(gè)參數(shù)self,就是這個(gè)__new__返回的實(shí)例,__init__在__new__的基礎(chǔ)上可以完成一些其它初始化的動(dòng)作,__init__不需要返回值
Ø 先執(zhí)行__new__再執(zhí)行__init__
Ø 我們可以將類比例制造商,__new__方法就是前期的原材料購(gòu)買環(huán)節(jié),__init__方法就是在有原材料的基礎(chǔ)上,加工,初始化商品環(huán)節(jié)
Ø class User(object):
def __init__(self, username, password):
self.username = username
self.password = password
print("對(duì)象已經(jīng)構(gòu)建好了,由解釋器自動(dòng)以回調(diào),對(duì)象初始化")
# new方法是當(dāng)對(duì)象構(gòu)建 的時(shí)候由解釋器自動(dòng)回調(diào)的方法。該方法必須返回當(dāng)前類的對(duì)象
def __new__(cls, username, password):
print("User類的對(duì)象開始構(gòu)建")
return object.__new__(cls) # 沒有返回構(gòu)建的對(duì)象時(shí),后面代碼不執(zhí)行,調(diào)用object類,構(gòu)建對(duì)象
def __str__(self):
return "用戶名%s;密碼%s"%(self.username,self.password)
u = User('ZhangSan','abc123')
print(u)
輸出:
User類的對(duì)象開始構(gòu)建
對(duì)象已經(jīng)構(gòu)建好了,由解釋器自動(dòng)以回調(diào),對(duì)象初始化
用戶名ZhangSan;密碼abc123
特殊方法名 | 默認(rèn)的參數(shù) | 功能描述 |
__init__() | self | 初始化對(duì)象屬性 |
__str__() | self | print對(duì)象時(shí),輸出 |
__del__() | self | 刪除對(duì)象 |
__new__() | cls | 創(chuàng)建對(duì)象 |
單例模式
單例模式例子:我們?nèi)粘J褂玫碾娔X 上都有一個(gè)回收站,在整個(gè)操作系統(tǒng)中,回收站只能有一個(gè)實(shí)例,整個(gè)系統(tǒng)都使用這個(gè)唯一的實(shí)例,而且回收站自行提供自己的實(shí)例,因此回收是單例模式的應(yīng)用。
確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例,這上類稱為單例類,單例模式是一種對(duì)象創(chuàng)建型模式
使用單例模式的類的特點(diǎn):
1. 在構(gòu)造過程中非常復(fù)雜,消耗大量?jī)?nèi)存資源
2. 封裝的大量數(shù)據(jù),可以當(dāng)全局變量用
【單實(shí)例模式1】
class User(object):
__instance = None
def __init__(self, name):
print("運(yùn)行__init__()方法")
self.name = name
@classmethod
def get_instance(cls, name):
print("運(yùn)行g(shù)et_instance()方法")
if not cls.__instance: # 一開始__instance = None 滿足條件,創(chuàng)建對(duì)象,
# 后面一直不滿足(只運(yùn)行一次),
# 不創(chuàng)建新的對(duì)象實(shí)例,后面的name不變
cls.__instance = User(name)
return cls.__instance
u1 = User.get_instance('ZhangSan')
print("u1的name為%s"%u1.name)
u2 = User.get_instance("LiSi")
print("u2的name為%s"%u2.name)
print("最后:u1的name為%s;u2的name為%s" % (u1.name,u2.name))
print(u1 == u2) # 判斷表達(dá)式,如果返回True,這兩具對(duì)象是一個(gè)對(duì)象,并且內(nèi)存地址相同
print("u1對(duì)象的內(nèi)存地址%s u2對(duì)象的內(nèi)存地址%s"%(id(u1), id(u2)))
輸出:
運(yùn)行get_instance()方法
運(yùn)行__init__()方法
u1的name為ZhangSan
運(yùn)行get_instance()方法
u2的name為ZhangSan
最后:u1的name為ZhangSan;u2的name為ZhangSan
True
u1對(duì)象的內(nèi)存地址2529384892176 u2對(duì)象的內(nèi)存地址2529384892176
【單實(shí)例模式2】
class User(object):
__instance = None
def __init__(self, name):
print("運(yùn)行__init__()方法")
self.name = name
def __new__(cls, name):
print("運(yùn)行__new__()方法")
if not cls.__instance: # 保證 object.__new__(cls)方法只會(huì)調(diào)用一次
cls.__instance = object.__new__(cls)
return cls.__instance
u1 = User('ZhangSan')
print("u1的name為%s" % u1.name)
u2 = User("LiSi")
print("u2的name為%s" % u2.name)
print("最后:u1的name為%s;u2的name為%s" % (u1.name,u2.name))
print(u1 == u2) # 判斷表達(dá)式,如果返回True,這兩具對(duì)象是一個(gè)對(duì)象,并且內(nèi)存地址相同
print("u1對(duì)象的內(nèi)存地址%s u2對(duì)象的內(nèi)存地址%s"%(id(u1), id(u2)))
輸出:
運(yùn)行__new__()方法
運(yùn)行__init__()方法
u1的name為ZhangSan
運(yùn)行__new__()方法
運(yùn)行__init__()方法
u2的name為LiSi
最后:u1的name為LiSi;u2的name為LiSi
True
u1對(duì)象的內(nèi)存地址1584795191056 u2對(duì)象的內(nèi)存地址1584795191056
簡(jiǎn)單工廠模式
工廠模式是我們最常用的實(shí)例化對(duì)象模式,是用工廠方法代替new操作的一種模式,雖然這樣做可能多做一些工作,但會(huì)給你系統(tǒng)帶來更大的可擴(kuò)展性和盡量少的修改量
解決兩個(gè)對(duì)象/兩個(gè)類之間存在依賴關(guān)系的時(shí)候的問題。提高系統(tǒng)的維護(hù)操作性。
簡(jiǎn)單工廠模式Simple Factory模式不是獨(dú)立的設(shè)計(jì)模式,是Factory Method模式的一種簡(jiǎn)單的、特殊的實(shí)現(xiàn)。也被稱為靜態(tài)工廠模式,通常創(chuàng)建都的創(chuàng)建方法被設(shè)計(jì)為static方便調(diào)用。包含:
1. 靜態(tài)的工廠類
2. 用全局函數(shù)改寫工廠類
【例1,靜態(tài)工廠類】
class Person(object):
def __init__(self, name):
self.name = name
def work(self, axe_type):
print(self.name+"開始工作了") # person完成work,需要一把斧頭
# 在原始社會(huì),需要一把石斧
# axe = StoneAxe("花崗巖斧頭") # 通過StoneAxe()生產(chǎn)斧頭
# axe = SteelAxe("江南十三子斧頭") # SteelAxe()生產(chǎn)斧頭
axe = Factory.create_axe(axe_type) # 通過 第三方工廠來生產(chǎn)斧頭
axe.cut_stree()
class Axe(object):
def __init__(self,name):
self.name = name
def cut_tree(self):
print("%s斧頭,開始砍樹"%self.name)
class StoneAxe(Axe):
def cut_stree(self):
print("使用%s做的斧頭砍樹"%self.name)
class SteelAxe(Axe):
def cut_stree(self):
print("使用%s的鋼斧頭砍樹"%self.name)
class Factory(object):
# 生產(chǎn)斧頭,根據(jù)用戶指標(biāo)的類型來生產(chǎn)
@staticmethod
def create_axe(type):
if type == "stone":
return StoneAxe("花崗巖斧頭")
elif type == "steel":
return SteelAxe("加爵斧頭")
else:
print("傳入的類型不對(duì)")
p = Person("ZhangSan")
p.work("steel")
例2,全局函數(shù)
class Person(object):
def __init__(self, name):
self.name = name
def work(self, axe_type):
print(self.name+"開始工作了") # person完成work,需要一把斧頭
# 在原始社會(huì),需要一把石斧
# axe = StoneAxe("花崗巖斧頭") # 通過StoneAxe()生產(chǎn)斧頭
# axe = SteelAxe("江南十三子斧頭") # SteelAxe()生產(chǎn)斧頭
axe = create_axe(axe_type)# 通過全局函數(shù)來生產(chǎn)斧頭
axe.cut_stree()
class Axe(object):
def __init__(self,name):
self.name = name
def cut_tree(self):
print("%s斧頭,開始砍樹"%self.name)
class StoneAxe(Axe):
def cut_stree(self):
print("使用%s做的斧頭砍樹"%self.name)
class SteelAxe(Axe):
def cut_stree(self):
print("使用%s的鋼斧頭砍樹"%self.name)
# 全局函數(shù)-替代之前的工廠類
def create_axe(type):
if type == "stone":
return StoneAxe("花崗巖斧頭")
elif type == "steel":
return SteelAxe("加爵斧頭")
else:
print("傳入的類型不對(duì)")
p = Person("ZhangSan")
p.work("steel")
工廠方法模式
工廠方法模式去掉了簡(jiǎn)單工廠模式中工廠方法的靜態(tài)方法,使得它可以被子類繼承,對(duì)于python來說,就是工廠類被具體工廠繼承。這樣在簡(jiǎn)單工廠模式里集中在方法上的壓力可以由工廠方法模式里不同的工廠子類來分擔(dān)。
抽象的工廠類提供了一個(gè)創(chuàng)建對(duì)象的方法,也叫作工作方法。
1) 抽象工廠角色(Factory):這是工廠方法模式的核心,它與應(yīng)用程序無關(guān),是具體工廠色必須 實(shí)現(xiàn)的接口或者必須 繼承的父類。
2) 具體工廠角色(Stone_Axe_Factory,Steel_Axe_Factory):它含有和具體業(yè)務(wù)邏輯有關(guān)的代碼。由應(yīng)用程序調(diào)用以創(chuàng)建不的具體產(chǎn)品時(shí)的對(duì)象
3) 抽象產(chǎn)品角色(Axe):它是具體產(chǎn)品繼承 的父類或者是實(shí)現(xiàn)的接口。在python中旬產(chǎn)品一般為父類。
4) 具體產(chǎn)品角色(Stone_Axe,Steel_Axe):具體工廠角色所創(chuàng)建的對(duì)象就是此角色 的實(shí)例,由一個(gè)具體在實(shí)現(xiàn)
class Person(object):
def __init__(self, name):
self.name = name
def work(self):
print(self.name+"開始工作了") # person完成work,需要一把斧頭
# 在原始社會(huì),需要一把石斧
# axe = StoneAxe("花崗巖斧頭") # 通過StoneAxe()生產(chǎn)斧頭
# axe = SteelAxe("江南十三子斧頭") # SteelAxe()生產(chǎn)斧頭
# axe = Steel_Axe_Factory.create_axe() # 通過 第三方工廠來生產(chǎn)斧頭
axe = Stone_Axe_Factory.create_axe() # 通過 第三方工廠來生產(chǎn)斧頭
axe.cut_stree()
class Axe(object):
def __init__(self,name):
self.name = name
def cut_tree(self):
print("%s斧頭,開始砍樹"%self.name)
class StoneAxe(Axe):
def cut_stree(self):
print("使用%s做的斧頭砍樹"%self.name)
class SteelAxe(Axe):
def cut_stree(self):
print("使用%s的鋼斧頭砍樹"%self.name)
# 工廠類
class Factory(object):
# 生產(chǎn)斧頭,根據(jù)用戶指標(biāo)的類型來生產(chǎn)
def create_axe(self):
pass
class Stone_Axe_Factory(Factory):
def create_axe():
return StoneAxe("花崗巖斧頭")
class Steel_Axe_Factory(Factory):
def create_axe():
return SteelAxe("鋼鐵斧頭")
p = Person("ZhangSan")
p.work()
內(nèi)建屬性
內(nèi)建屬性 |
常用專用有屬性 | 說明 | 觸發(fā)方式 |
__init__ | 構(gòu)造初始化函數(shù) | 創(chuàng)建實(shí)例后,賦值時(shí)使用,在__new__后 |
__new__ | 生成實(shí)例所需屬性 | 創(chuàng)建實(shí)例時(shí) |
__class__ | 實(shí)例所在的類 | 實(shí)例__class__ |
__str__ | 實(shí)例字符串表示,可讀性 | print(類實(shí)例),如沒實(shí)現(xiàn),使用repr結(jié)果 |
__repr__ | 實(shí)例字符串表示,準(zhǔn)確性 | 類實(shí)例,回車 或都print(repr(類實(shí)例)) |
__del__ | 析構(gòu) | del 刪除實(shí)例 |
__dict__ | 實(shí)例自定義屬性 | vars(實(shí)例__dict__) |
__doc__ | 類文檔,子類不繼承 | help(類或?qū)嵗?/span>) |
__getattribute__ | 屬性訪問攔截器 | 訪問實(shí)例屬性時(shí) |
__bases__ | 類的所有父類 構(gòu)成元素 | 類名__bases__ |
例__getattribute__屬性訪問攔截器
屬性訪問攔截器的坑:

限制任性對(duì)象的屬性__slots__
注意,__slots__定義的屬性公對(duì)當(dāng)前類實(shí)例起作用,對(duì)繼承的子類是不起作用的

類裝飾器
裝飾器函數(shù)其實(shí)是這樣一個(gè)接口約束,它必須接受一個(gè)callable對(duì)象作為參數(shù),然后返回一個(gè)callable對(duì)象。
一般callable對(duì)象都是函數(shù),但也有例外。只要某個(gè)對(duì)象重寫了__call__()方法,那么這個(gè)對(duì)象就是callable的
例:類當(dāng)函數(shù)用

例2類裝飾器

