名詞:
OOP程式設計是利用“類”和“對象”來建立各種模型來實作對真實世界的描述,使用面向對象程式設計的原因一方面是因為它可以使程式的維護和擴充變得更簡單,并且可以大大提高程式開發效率 ,另外,基于面向對象的程式可以使它人更加容易了解你的代碼邏輯,進而使團隊開發變得更從容。
面向對象的幾個核心特性如下
Class 類
一個類即是對一類擁有相同屬性的對象的抽象、藍圖、原型。在類中定義了這些對象的都具備的屬性(variables(data))、共同的方法, 例如人類,蛇類,貓科類
Object 對象
一個對象即是一個類的執行個體化後執行個體,一個類必須經過執行個體化後方可在程式中調用,一個類可以執行個體化多個對象,每個對象亦可以有不同的屬性,就像人類是指所有人,每個人是指具體的對象,人與人之前有共性,亦有不同,比如類(人類)----》對象(隔壁老王)
Encapsulation 封裝
在類中對資料的指派、内部調用對外部使用者是透明的,這使類變成了一個膠囊或容器,裡面包含着類的資料和方法
Inheritance 繼承
一個類可以派生出子類,在這個父類裡定義的屬性、方法自動被子類繼承
Polymorphism 多态
多态是面向對象的重要特性,簡單點說:“一個接口,多種實作”,指一個基類中派生出了不同的子類,且每個子類在繼承了同樣的方法名的同時又對父類的方法做了不同的實作,這就是同一種事物表現出的多種形态。
程式設計其實就是一個将具體世界進行抽象化的過程,多态就是抽象化的一種展現,把一系列具體事物的共同點抽象出來, 再通過這個抽象的事物, 與不同的具體事物進行對話。
對不同類的對象發出相同的消息将會有不同的行為。比如,你的老闆讓所有員工在九點鐘開始工作, 他隻要在九點鐘的時候說:“開始工作”即可,而不需要對銷售人員說:“開始銷售工作”,對技術人員說:“開始技術工作”, 因為“員工”是一個抽象的事物, 隻要是員工就可以開始工作,他知道這一點就行了。至于每個員工,當然會各司其職,做各自的工作。
多态允許将子類的對象當作父類的對象使用,某父類型的引用指向其子類型的對象,調用的方法是該子類型的方法。這裡引用和調用方法的代碼編譯前就已經決定了,而引用所指向的對象可以在運作期間動态綁定
類的變量和執行個體變量
類變量:大家共用的屬性,在執行個體化不會建立在執行個體的記憶體中,可以節省開銷。
執行個體變量:描述每個執行個體的屬性
class Dog:#建立一個Dog類
n=123#類變量
name='page' #類變量
def __init__(self,name,age): #類屬性
self.name=name
self.age=age
def wang(self,name):類方法
print("%s is wang"%name)
Dog.n="nihaho"
d1=Dog("index",12)
d1.n=12345
print(d1.n)
d2=Dog("home",13)
print(d2.n)
列印結果
12345
nihaho
當執行個體調用類變量,并且給類變量指派時,類變量會在執行個體的記憶體拷貝一份。修改類變量,執行個體調用的類變量不會變。12345
當執行個體僅調用類變量,這時類變量在類的記憶體中,修改類變量,執行個體調用的類變量會變。nihao
封裝:
上面程式生成執行個體d1=Dog("index",12),隻需傳入參數,執行個體也可以調用很多方法。但是内部是怎麼實作的是看不見的,是以類起到了一個封裝的作用。
繼承:
單繼承
#class People:經典類
class People(object):#新式類
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print("%s is eating..."%self.name)
def talk(self):
print("%s is talking..."%self.name)
def sleep(self):
print("%s is sleeping..."%self.name)
class Man(People):#繼承父類
def __init__(self,name,age,money):
People.__init__(self,name,age) #重構父類屬性 經典類繼承寫法
#super(Man,self).__init__(name,age) super方法也可以 新式類繼承寫法
self.money=money
print("%s一出生就有%s錢"%(self.name,self.money))
def see(self):
print("%s is see...."%self.name)
# def sleep(self):
# print("man is sleepiong...") 這是完全覆寫父類方法
def sleep(self):
People.sleep(self) #重構父類方法
print("man is sleeping...")
class Women(People):
def drunk(self):
print("%s is drunk ...."%self.name)
m1=Man("bob",22,10)
m1.eat()
m1.see()
m1.sleep()
w1=Women("alice",21)
w1.drunk()
多繼承
class People(object):
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print("%s is eating..."%self.name)
def talk(self):
print("%s is talking..."%self.name)
def sleep(self):
print("%s is sleeping..."%self.name)
class Relation(object):
def make_friends(self,obj):
print("%s is make friends with %s"%(self.name,obj.name))
class Man(People,Relation):
def __init__(self,name,age,money):
#People.__init__(self,name,age) #重構父類屬性 經典類繼承寫法
super(Man,self).__init__(name,age) #super方法也可以 新式類繼承寫法
self.money=money
print("%s一出生就有%s錢"%(self.name,self.money))
def see(self):
print("%s is see...."%self.name)
def sleep(self):
People.sleep(self)
print("man is sleeping...")
class Women(People,Relation):
def drunk(self):
print("%s is drunk ...."%self.name)
m1=Man("bob",22,10)
# m1.eat()
# m1.see()
# m1.sleep()
w1=Women("alice",21)
# w1.drunk()
m1.make_friends(w1)
python 支援多繼承,但對與經典類和新式類來說,多繼承查找的順序是不一樣的。
py2 經典類是按深度優先來繼承的,新式類是按廣度優先來繼承的
py3 經典類和新式類都是統一按廣度優先來繼承的
深度優先
class P1:
def foo(self):
print 'p1-foo'
class P2 :
def foo(self):
print 'p2-foo'
def bar(self):
print 'p2-bar'
class C1 (P1,P2):
pass
class C2 (P1,P2):
def bar(self):
print 'C2-bar'
class D(C1,C2):
pass
執行結果
d = D()
d.foo() # 輸出 p1-foo
d.bar() # 輸出 p2-bar
執行個體d調用foo()時,搜尋順序是 D => C1 => P1
執行個體d調用bar()時,搜尋順序是 D => C1 => P1 => P2
換句話說,經典類的搜尋方式是按照“從左至右,深度優先”的方式去查找屬性。d先查找自身是否有foo方法,沒有則查找最近的父類C1裡是否有該方法,如果沒有則繼續向上查找,直到在P1中找到該方法,查找結束。
廣度優先
class P1(object):
def foo(self):
print 'p1-foo'
class P2(object):
def foo(self):
print 'p2-foo'
def bar(self):
print 'p2-bar'
class C1 (P1,P2):
pass
class C2 (P1,P2):
def bar(self):
print 'C2-bar'
class D(C1,C2):
pass
執行結果
d=D()
d.foo() # 輸出 p1-foo
d.bar() # 輸出 c2-bar
執行個體d調用foo()時,搜尋順序是 D => C1 => C2 => P1
執行個體d調用bar()時,搜尋順序是 D => C1 => C2
可以看出,新式類的搜尋方式是采用“廣度優先”的方式去查找屬性。
多态:
多态性(polymorphisn)是允許你将父對象設定成為和一個或更多的他的子對象相等的技術,指派之後,父對象就可以根據目前指派給它的子對象的特性以不同的方式運作。簡單的說,就是一句話:允許将子類類型的指針指派給父類類型的指針。 那麼,多态的作用是什麼呢?我們知道,封裝可以隐藏實作細節,使得代碼子產品化;繼承可以擴充已存在的代碼子產品(類);它們的目的都是為了——代碼重用。而多态則是為了實作另一個目的——接口重用!多态的作用,就是為了類在繼承和派生的時候,保證使用“家譜”中任一類的執行個體的某一屬性時的正确調用。 Pyhon 很多文法都是支援多态的,比如 len(),sorted(), 你給len傳字元串就傳回字元串的長度,傳清單就傳回清單長度。 Python多态示例
class Animal(object):
def __init__(self, name): # Constructor of the class
self.name = name
def talk(self): # Abstract method, defined by convention only
raise NotImplementedError("Subclass must implement abstract method")
class Cat(Animal):
def talk(self):
print('%s: miao miao!' %self.name)
class Dog(Animal):
def talk(self):
print('%s: wang wang' %self.name)
def func(obj): #一個接口,多種形态
obj.talk()
c1 = Cat('index')
d1 = Dog('home')
func(c1)
func(d1)
執行結果
index: miao miao!
home: wang wang
func這是一個接口,輸入不同的對象,輸出結果不同,一個接口多種形态.
類的靜态方法:
靜态方法 隻是名義上歸類管理, 實際上在靜态方法裡通路不了類或執行個體中的任何屬性
class Dog(object):
def __init__(self,name):
self.name=name
@staticmethod #類的靜态
def eat(self):
print("%s is eating %s"%(self.name,'baozi'))
d1=Dog("alice")
d1.eat(d1)#把執行個體傳進去
類方法:
隻能通路類變量,不能通路執行個體變量
class Dog(object):
name="bob" #如果吧name注釋 程式出錯
def __init__(self,name):
self.name=name
#@staticmethod #類的靜态方法
@classmethod #類方法
def eat(self):
print("%s is eating %s"%(self.name,'baozi'))
d1=Dog("alice")
# d1.eat(d1)#把執行個體傳進去
d1.eat()
列印結果
bob is eating baozi
屬性方法:
把一個方法變成一個靜态屬性
class Flight(object):
def __init__(self,name):
self.flight_name = name
def checking_status(self):
print("checking flight %s status " % self.flight_name)
return 0
@property
def flight_status(self):
status = self.checking_status()
if status == 0 :
print("flight got canceled...")
elif status == 1 :
print("flight is arrived...")
elif status == 2:
print("flight has departured already...")
else:
print("cannot confirm the flight status...,please check later")
@flight_status.setter
def flight_status(self,status):
print("flight %s has changed status to %s" %(self.flight_name,status))
f = Flight("CA980")
f.flight_status
屬性方法的用途如上
反射:
通過字元串映射或修改程式運作時的狀态、屬性、方法, 有以下4個方
hasattr(obj,name)判斷object中有沒有一個name字元串對應的方法或屬性
getattr(obj,name)根據字元串去擷取obj對象裡的對應的方法的記憶體位址
舉例
class Dog(object):
def __init__(self,name):
self.name=name
def eat(self):
print("%s is eating...",self.name)
d=Dog("alice")
choice=input(">>:").strip()
# print(hasattr(d,choice))
#
# print(getattr(d,choice))
# getattr(d,choice)()
if hasattr(d,choice): 判斷object中有沒有一個name字元串對應的方法或屬性
func=getattr(d,choice)根據字元串去擷取obj對象裡的對應的方法的記憶體位址
func()調用
輸入字元串調用執行個體的方法.
setattr(obj,name)# real signature unknown; restored from __doc__
"""
Sets the named attribute on the given object to the specified value.
setattr(x, 'y', v) is equivalent to ``x.y = v''
delattr(x,y)#real signature unknown; restored from __doc__
"""
Deletes the named attribute from the given object.
delattr(x, 'y') is equivalent to ``del x.y''
"""
def bulk(self):
print(" %s is jiao ...",self.name)
class Dog(object):
def __init__(self,name):
self.name=name
def eat(self):
print("%s is eating...",self.name)
d=Dog("alice")
choice=input(">>:").strip()
# print(hasattr(d,choice))
#
# print(getattr(d,choice))
# getattr(d,choice)()
if hasattr(d,choice):
func=getattr(d,choice)
func()
else:
setattr(d,choice,bulk) 給類增加一個屬性
d.talk(d)
注: 參考 http://www.cnblogs.com/alex3714/articles/5213184.html
轉載于:https://www.cnblogs.com/cui0x01/p/8567092.html