以下概念及舉例均在python3.*中實作;
1、
面向過程&面向對象:
op
oo
産生背景
科學計算為目标的必然産物
軟體應用領域的擴張和系統膨脹之後應運而生
程式設計方法
自頂向下
自底向上
代碼主體結構
程式=資料(變量)+算法(函數|過程)
程式=對象+互動
資料操作主體
由函數|過程進行加工與展現
在對象的方法中加工與展現
模拟方法
通過函數|過程操縱表現世界的資料與狀态
把世界描繪成具有主動性的對象之間互動
程式設計思維
搞清處理資料的步驟
面向對象分析
運作效率
較高
較低
雞兔同籠:
先假設全部為雞,計算出腿數;
算出腿數量差;
得出雞數量;
計算另一動物的數量;
注:
自猜想的資料類型;
變量名為大寫就認為是常量;
大小寫敏感;
2、
對象程式設計體驗:
自動運作小遊戲模拟:
在一維的地圖上,有一隻蟲子和一隻螞蟻,每一次它們都走過一個-3,-2,2,3随機機關的距離(標明走法),若達到地圖邊界則放棄移動,當螞蟻蟲子處于同一位置時,螞蟻吃掉蟲子,程式結束;
op:
蟲子的初始位置;
螞蟻的初始位置;
進入循環(條件為螞蟻和蟲子不在同一位置);
依照規則,螞蟻和蟲子移動位置;
直到螞蟻和蟲子走到同一位置,程式結束;
oo:
遊戲中的對象有:地圖、蟲子、螞蟻;
地圖是一維的,隻需要記錄蟲子和螞蟻的位置;
螞蟻和蟲子知道自己的位置;
螞蟻和蟲子能按規則移動;
定義地圖、螞蟻、蟲子三個類;
主程式中執行個體化它們,并通過對象間的互動來完成遊戲的模拟;
3、
面向對象入門:
了解對象:
對象可以指自然界中的任何事物;
計算機為解決某個領域問題所使用的事物(自然界中的事物的模型化);
事物(對象)隻有自身的特征或能力;
計算機中的對象具有解決問題所需的特征或能力;
對象優越性:
封裝(将模型的特征和能力打包在一起;模型的改變由模型自身來完成,就像自然界的事物一樣;隐藏模型的細節,外界隻能使用它,而不必(不能)改變它);
繼承(符合自然界的分類規律;快速的代碼重用);
多态(子類可以繼承父類的特征與能力,還可通過自定義來修改其特征與能力;duck typing鴨子類型);
組合(一個模型可以由其它的模型組成);
duck typing來源于james whitcomb riley提出的鴨子測試:
當看到一隻鳥走起來像鴨子,叫起來像鴨子,遊泳起來像鴨子,那麼這隻鳥就可被稱為鴨子;
在鴨子類型中,關注的不是對象的類型本身,而是它是如何使用的;
在有的語言中必須用接口來實作;
4、
定義和使用類:
最簡類定義;
類執行個體化;
類與執行個體之間的關系(
定義類就是建立模型;
執行個體化就是建立真實事物;
例如:模具、印章);
有特征和能力的類(
特征|屬性,是類自身包含或知道的資料;
能力,以方法展現,是類具有能動性的展現);
執行個體化步驟(
調用__new__()方法建立執行個體,__new__()方法自動從object繼承;
調用__init__()方法對其初始化,__init__()方法在類中定義);
添加類說明docstring(
緊跟在類名之後,以三引号包圍的字元串;
檢視類說明,類名.__doc__或help(類名));
新式類與經典類(
python2.*版本,預設是經典類,繼承object為新式類;
python3.*版本,統一為新式類,不用繼承object;
差別:經典類繼承為深度優先;新式類繼承為廣度優先)
描述對象的特征(執行個體屬性;類屬性;私有屬性;特殊屬性):
執行個體屬性:
類被執行個體化以後才具有的屬性;
一般在__init__()方法中建立并初始化;
直接使用即定義,self.屬性名;
引用方法,self.屬性名;
self用來代表類的執行個體;
類外用執行個體名.屬性名方式定義和引用;
相同類的不同執行個體,其執行個體屬性是不相關的;
一般不建議在__init__()方法之外建立和初始化執行個體屬性;
一般不推薦類外定義和修改,修改可以單獨定義方法;
In [13]: class TestClass:
....: def __init__(self):
....: self.a = 0
....: self.b = 10
....: def info(self):
....: print 'a:',self.a,'b:',self.b
....: def define_c(self):
....: self.c = 20
In [14]: tc=TestClass()
In [15]: tc.info()
a: 0 b: 10
In [16]: tc.color='red' #類外用
In [17]: print tc.color
red
In [18]: tca = TestClass()
In [19]: tcb = TestClass()
In [20]: tca.a = 100
In [21]: tcb.a = 200
In [22]: tca.info()
a: 100 b: 10
In [23]: tcb.info()
a: 200 b: 10
In [24]: tc = TestClass()
In [25]: tc.define_c()
In [26]: print tc.c
20
類屬性:
類定義後就存在,而且不需要執行個體化;
類屬性使得相同類的不同執行個體共同持有相同變量;
In [27]: class TestCss:
....: cssa = 'class-attribute'
....: print 'a:',self.a,'b:',self.b,TestCss.cssa
In [29]: tc = TestCss()
In [30]: tc.info()
a: 0 b: 10 class-attribute
In [31]: tca = TestCss()
In [33]: tca.info()
In [34]: TestCss.cssa = 0 #類外修改其屬性
In [35]: tc.info()
a: 0 b: 10 0
In [36]: tca.info()
私有屬性:
不提供限制屬性通路的關鍵字(無法限制類的各種屬性在類外直接通路);
使用__開頭的變量名加以标示,隻有類對象自己能通路(限制性的);
使用_開頭的變量名加以标示,隻有類對象及其子類能通路(非強制性),對程式員來說,是标示性的而非限制性的,在類外還可以修改和檢視;
In [37]: class TestPri:
....: self.__a = 0 #在此處初始化時執行個體屬性就被隐藏了
....: print self.__a
....:
In [38]: a = TestPri()
In [39]: a.info()
In [40]: a.__a = 3 #私有屬性不能在外部進行修改,此處相當于重新定義了一個執行個體屬性,與類中定義的self.__a = 0是不一樣的
In [41]: a.info()
In [43]: print a.__a
3
In [44]: class TestPri:
....: self._a = 10
....: print self._a
In [45]: a = TestPri()
In [46]: a.info()
10
In [47]: a._a = 30 #在類外可修改和檢視
In [48]: a.info()
30
In [49]: print a._a
特殊屬性:
__doc__
__name__ #類名稱
__dict__ #執行個體屬性的所有屬性名及值組成的dictionary
__module__ #該類所在的子產品名
__base__ #該類的父類
5、讓對象具有能動性:
類的方法的定義:
def fun_name(self,…):
pass
其中,self表示類的執行個體,在調用方法時由系統自動提供;
方法定義時必須指明self參數;
類的方法的調用:
與普通函數調用類似,即使參數清單為空也不能省略();
在類的内部調用,self.方法名(參數清單);
在類的外部調用,執行個體名.方法名(參數清單);
以上兩種調用方法,提供的參數清單中都不用包括self;
類内方法互相調用:
在一個類的内部,方法之間是可以互相調用的;
調用方法,self.方法名(參數清單);
構造方法及其作用:
構造方法即使用__init__()方法;
構造方法的作用是在類執行個體化時初始化執行個體;
__init__()方法就是類執行個體化的第二步自動調用的函數,其方法名是固定的,但其參數同普通方法一樣,至少要帶self參數;
初始化執行個體包括,定義和初始化執行個體屬性,或調用類的一些方法;
構造方法可帶有除self外的其它各種參數,關鍵字參數、預設參數、用tuple收集參數、用字典收集關鍵字參數等,可以達到在執行個體化類時,為相應的屬性傳入指定的值;
定義類的執行個體方法,和執行個體屬性一樣,必須進行類執行個體化之後,才能存在和調用它們;
python3.*版本,print是函數;python2.*,print是語句;
6、深入類的屬性:
同名的類屬性與執行個體屬性:
執行個體名.屬性名,優先引用執行個體屬性;
類名.屬性名,隻能引用類屬性;
屬性通路的特殊方法(反射,或叫自省):
用字元串來操作類的屬性|方法的方式;
主要工具函數(在編寫架構或特殊項目時才用到):
hasattr(obj_name,'屬性名')
setattr(obj_name,'屬性名',值)
getattr(obj_name,'屬性名')
In [50]: class TestClass:
....: a = 0
....: self.a = 10
....: self.b = 20
In [51]: a = TestClass()
In [52]: a.a
Out[52]: 10
In [53]: a.b
Out[53]: 20
In [54]: TestClass.a
Out[54]: 0
In [55]: TestClass.b #抛異常,此類未定義b屬性
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-55-39cab4ae7dc4> in <module>()
----> 1 TestClass.b
AttributeError: class TestClass has no attribute 'b'
In [56]: getattr(a,'a') #擷取執行個體a的a屬性
Out[56]: 10
In [57]: setattr(a,'a',20)
In [58]: a.a
Out[58]: 20
In [59]: hasattr(a,'b')
Out[59]: True
屬性包裝:
将方法包裝成屬性,以隐藏相關實作,使用者使用時用屬性的方式來用;
控制屬性的類型和範圍,如某屬性隻能是正數且在0-100之間;
虛拟屬性(由其它屬性處理後得來);
三種屬性操作(3個裝飾器):
@property #可讀
@<property-name>.setter #可寫
@<property-name>.deleter #可删
舉例:
attribute_package.py
#!/usr/bin/env python3.6
#
class Washer:
def __init__(self,water=100,scour=2):
self._water = water
self.scour = scour
self.year = 2010
@property
def water(self):
return self._water
@water.setter
def water(self,water):
if 0 < water <= 500:
self._water = water
else:
print('set failure')
def total_year(self):
return 2018 - self.year
if __name__ == '__main__':
w = Washer()
print(w.water)
w.water = -123
print(w.total_year)
描述符:
将實作特殊協定方法的類作為另一個類的類屬性;
用來攔截和控制屬性通路并可重複使用;
協定方法:
__get __()
__set__()
__delete__()
分類:
資料描述符(實作全部協定方法);
非資料描述符(實作部分協定方法);
說明:
所有類成員函數都是非資料描述符;
同名的執行個體屬性和非資料描述符(以方法為例)通路優先級;
描述符隻能在新式類中使用;
__call__(),讓類的執行個體如函數一樣可調用;
舉例(資料描述符):
data_description.py
class NonNeg:
def __init__(self,default=0):
self.default = default
def __get__(self,instance,owner):
return self.default
def __set__(self,instance,val):
if val > 0:
self.default = val
print('the value must be nonnegative')
def __delete__(self,instance):
pass
class Movie:
rating = NonNeg()
score = NonNeg()
m = Movie()
print('rating:',m.rating)
print('score:',m.score)
m.rating = 80
m.score = 30
舉例(非資料描述符):
In [1]: class Test:
...: def pr(self):
...: print('test')
...:
In [2]: t = Test()
In [3]: dir(t.pr) #pr方法實作了__get__()方法
Out[3]:
['__call__',
'__class__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__func__',
'__ge__',
'__get__',
'__getattribute__',
In [4]: t.pr = 10 #執行個體屬性和非資料描述符同名,優先級為先執行個體屬性再非資料描述符,此例中t.pr的屬性掩蓋了pr()方法
In [5]: t.pr
Out[5]: 10
In [6]: del t.pr
In [7]: t.pr
Out[7]: <bound method Test.pr of <__main__.Test object at 0x7f10ecd1c1d0>>
In [8]: t.pr()
test
7、
類方法、靜态方法:
靜态方法:
定義:
用staticmethod裝飾;
參數不用self;
通路特性:
不能引用或通路執行個體屬性;
可通過類、類變量通路類屬性;
調用方式:
可用類、類執行個體調用;
本質:
在類中的一個普通函數;
使面向對象程式中的函數歸屬于類,易于代碼管理;
用法:
與類相關,但不依賴或改變類與執行個體;
建立不同的執行個體;
把類相關工具方法放入類中;
static_method.py
company = 'panasonic'
def __init__(self,water=10,scour=2):
self.water = water
@staticmethod
def spins_ml(spins):
print('company:',Washer.company)
#print('year:',self.year) #報錯,不能引用執行個體屬性
return spins * 0.4
print(Washer.spins_ml(8))
print(w.spins_ml(9))
w = Washer(200,Washer.spins_ml(10))
print(w.company)
print(w.year)
print(w.scour)
print(w.spins_ml(10))
類方法:
@classmethod;
必須提供參數cls;
通路特性:不能引用或通路執行個體屬性;
調用方法:可以用類、類執行個體調用;
繼承特性:傳入的類變量cls是子類,而非父類;
用途:
與類相關,但不依賴或改變類的執行個體;
工廠方法,建立類執行個體,完成有關預處理;
在類内調用靜态方法時不用寫死類名;
class_method.py
return spins * 0.4
@classmethod
def get_washer(cls,water,scour):
#print('year:',self.year)
return cls(water,cls.spins_ml(scour))
def start_wash(self):
print(self.water)
print(self.scour)
print('start wash')
w = Washer.get_washer(100,8)
w.start_wash()
8、
類的繼承與方法重載:
繼承特點:
oo程式設計的優點之一;
減少代碼和靈活制定新類;
子類具有父類的屬性和方法;
子類不能繼承父類的私有屬性|方法;
子類可添加新的方法;
子類可修改父類的方法;
繼承文法:
定義類時,在類名後寫(繼承的類名);
多重繼承時,括号中放多個父類名;
例:
class MyClass(BaseClass):
重載的文法:
直接定義和父類同名的方法;
修改父類的方法:
在重載的方法中調用父類方法;
同時添加相應的業務邏輯;
多重繼承時如何調用父類方法;
模拟遊戲解析:
sprite,ant,worm
例(編寫一個色子類):
1、具有6個面,每個面為一種顔色;
2、每種顔色代表一種數值1-6;
3、實作一個通過顔色計算兩種其代表數值和的靜态方法;
4、實作一個類方法gen_dice,用于産生這個類的執行個體;
In [2]: class A:
...: pass
...:
In [3]: A.__base__ #類A的父類是object,object是python中的新式類
Out[3]: object
In [4]: class B(A):
In [5]: B.__base__ #類B的父類是類A
Out[5]: __main__.A
In [6]: class C:
In [7]: class D(A,C):
In [8]: D.__bases__ #D的所有父類
Out[8]: (__main__.A, __main__.C)
In [9]: class A:
...: def foo(self):
...: print('A foo')
In [10]: class B:
....: def foo(self):
....: print('B foo')
In [11]: class C(A,B):
....: pass
....:
In [12]: c = C()
In [13]: c.foo() #輸出先繼承的類的方法
A foo
In [14]: class D(B,A):
In [15]: D().foo()
B foo
wash.py
9、
類的特殊方法:
深入了解類:
類也是一個對象,但具有建立其自身執行個體的能力;
類可以和一個變量進行綁定;
可以為類增加屬性;
可把類作為函數的參數傳遞;
元類:
類的建立和管理者type;
所有的類都是元類type的執行個體(python3.*);
類執行個體化過程;
In [16]: class Empty:
In [17]: ept = Empty
In [18]: ept
Out[18]: __main__.Empty
In [19]: ept.__base__
Out[19]: object
In [20]: ept()
Out[20]: <__main__.Empty at 0x7fd0adf7c470>
In [21]: ept.foo='foo'
In [22]: ept.foo
Out[22]: 'foo'
In [23]: def use_class(mc):
....: return mc()
In [25]: use_class(Empty)
Out[25]: <__main__.Empty at 0x7fd0adf7ef28>
In [26]: type(Empty)
Out[26]: type
In [27]: Hello = type('Hello',(object,),dict(helo=lambda lf:print('hello')))
In [28]: h = Hello()
In [29]: h.helo()
hello
10、
鴨子類型與多态:
多态:
一種類型具有多種類型的能力;
允許不同的對象對同一消息作出靈活的反應;
以一種通用的方式對待可使用的對象;
非動态語言必須通過繼承和接口來實作;
python中的多态:
通過繼承實作多态(子類可作為父類使用);
子類可重載父類的方法實作多态;
In [31]: class Animal:
....: def move(self):
....: print('Animal is moving...')
In [32]: class Dog(Animal):
In [33]: def move(obj):
....: obj.move()
....:
In [34]: a = Animal()
In [35]: move(a)
Animal is moving...
In [36]: d = Dog()
In [37]: move(d)
In [38]: class Cat(Animal):
....: print('Cat is moving...')
In [41]: class Sheep(Animal):
....: print('Sheep is moving...')
In [42]: move(Cat())
Cat is moving...
In [43]: move(Sheep())
Sheep is moving...
In [44]: move(7) #報錯
動态語言與鴨子類型:
變量綁定的類型具有不确定性;
函數和方法可接受任何類型的參數;
調用方法時不檢查提供的參數類型;
調用時是否成功由參數的方法和屬性确定;
調用不成功則抛出錯誤;
python中不用定義接口;
In [48]: def test(foo):
....: print(type(foo))
In [49]: test(3)
<class 'int'>
In [50]: test(3.1)
<class 'float'>
In [51]: type(3)
Out[51]: int
In [52]: type(3.1)
Out[52]: float
多态的好處:
可實作開放的擴充與修改的封閉;
使python更具靈活性;
11、
python與設計模式:
設計模式:
用來提高代碼複用和可維護性的方式;
能夠很好的指導軟體設計過程;
是成功的軟體設計模式和體系結構;
用于解決特定類型問題的面向對象程式設計模型;
由于語言的特性不同,設計模式的實作方式和實作難度也會不同;
有的模式已經在語言中内置了,如疊代器模式;
單例模式可直接用子產品級變量來實作;
普通工廠模式可直接通過傳入“類名”作為參數實作;
政策模式:
讓一個對象的某個方法可以随時改變,而不用更改對象的代碼;
對于動态類型的python語言,不需要定義接口;
基本的實作方法,用類作為參數傳遞;
最簡單的執行個體方法,函數作為參數傳遞;
例(單例模式):
single_class.py
class singleClass:
def __init__(self,x=0):
self.x = 0
sc = singleClass()
def tsc():
print(sc.x)
sc.x = 10
def tsc2():
sc.x = 9
tsc()
tsc2()
例(實作單執行個體的方式):
singleton.py
class Singleton:
def __new__(cls,*args,**kwargs):
if not hasattr(cls,'_sgl'):
cls._sgl = super().__new__(cls,*args,**kwargs)
return cls._sgl
sa = Singleton()
sb = Singleton()
print(id(sa))
print(id(sb))
例(普通工廠模式):
normal_factory.py
class Ab:
a = 3
class Ac:
a = 0
class MyFactory:
def get_instance(self,ins):
return ins()
mf = MyFactory()
print(type(mf.get_instance(Ab)))
例(政策模式——用類作為參數傳遞):
class Moveable:
def move(self):
print('Move...')
class MoveOnFeet(Moveable):
print('Move on feet...')
class MoveOnWheel(Moveable):
print('Move on wheel...')
class MoveObj:
def set_move(self,moveable):
self.moveable = moveable()
self.moveable.move()
class Test:
print('i am fly')
m = MoveObj()
m.set_move(Moveable)
m.move()
m.set_move(MoveOnFeet)
m.set_move(MoveOnWheel)
m.set_move(Test)
例(政策模式——用函數作為參數傳遞):
def movea():
print('move a')
def moveb():
print('move b')
self.moveable = moveable
self.moveable()
m.set_move(movea)
m.set_move(moveb)
12、
裝飾模式:
一般,通過繼承可獲得父類的屬性,還可通過重載修改其方法;
裝飾模式可不以繼承的方式而傳回一個被修改的類;
類裝飾器;
decorator.py
class BeDeco:
def be_edit_fun(self):
print('source fun')
def be_keep_fun(self):
print('keep fun')
class Decorator:
def __init__(self,dec):
self._dec = dec()
print('start...')
self._dec.be_edit_fun()
self._dec.be_keep_fun()
bd = BeDeco()
bd.be_edit_fun()
bd.be_keep_fun()
dr = Decorator(BeDeco)
dr.be_edit_fun()
dr.be_keep_fun()
def deco(a_class):
class NewClass:
def __init__(self,age,color):
self.wrapped = a_class(age)
self.color = color
def display(self):
print(self.color)
print(self.wrapped.age)
return NewClass
@deco
class Cat:
def __init__(self,age):
self.age = age
def display(self):
print(self.age)
c = Cat(12,'black')
c.display()
13、
通過組合來建構複雜的對象:
組合:
類似用各種零件組裝機器(零件——基礎類,機器——包含其它類的類);
展現自下而上的面向對象程式設計方法;
雪人案例:
面向對象分析;
抽象出其類;
實作基類(shape不帶角度參數的圖形元素;shapeAngles需要角度參數的圖形元素);
實作子類(HatTop,HatBotton,Face,Sense,BodyOutline,Button);
組裝子類1(Hat,Head,Body,Shape);
組裝子類2(snow);
本文轉自 chaijowin 51CTO部落格,原文連結:http://blog.51cto.com/jowin/2055034,如需轉載請自行聯系原作者