<a href="https://www.cnblogs.com/wupeiqi/p/4766801.html" target="_blank">https://www.cnblogs.com/wupeiqi/p/4766801.html</a>
<a href="https://www.cnblogs.com/paomaliuju/p/5122761.html" target="_blank">https://www.cnblogs.com/paomaliuju/p/5122761.html</a>
<a href="https://www.cnblogs.com/goser/articles/7097728.html" target="_blank">https://www.cnblogs.com/goser/articles/7097728.html</a>
<a href="http://www.cnblogs.com/alex3714/articles/5213184.html" target="_blank">http://www.cnblogs.com/alex3714/articles/5213184.html</a>
<a href="https://www.cnblogs.com/cenyu/p/5713686.html" target="_blank">https://www.cnblogs.com/cenyu/p/5713686.html</a>
本文是各篇文章優點的綜合,适合有一定基礎的朋友進行個人知識梳理
為了表示對前輩們的尊敬,以下均為純手打,代碼已經在2.7和3.6.3版本的python中測試過,并進行了修改,和注釋整理,以確定最通俗易懂。
首先回顧一下上節知識點
1,面向對象是一種很重要的程式設計方式,此程式設計方式的實作主要是通過類和對象的使用來實作的
2,在類中儲存有多個需要的函數
3,對象,使用類這個模闆,來進行更加具體的執行個體化,主要用于調用被包裝在類中的函數。
4,面向對象三大屬性:封裝,繼承和多态
5,python中新式類和經典類的粗淺比較用法
6,深度優先和廣度優先的第一核心概念解釋以及第二爬蟲中具體運用的解釋。
那麼這次分享,将會是如下部分:
面向對象進階文法部分
經典類vs新式類核心
字段,屬性
靜态方法、類方法、屬性方法
類的特殊方法
反射
謝謝大家啦(微笑)。
第一部分:
五星級:經典類和新式類的比較用法(重要)
(注:經典類的代碼有的需要在2.7中運作,請提前下好)
在python2及以前的版本中,由任意内置類型派生出來的類(隻要有一個内置類型位于類樹的某個位置)都屬于新式類,反之,即不由任意内置類型派生出來的類,則稱之為“經典類”。
關于内置類型的名詞解釋:
新式類”和“經典類”的區分在python3
“内置類型是指任何語言在設計初期定義的類型,如c語言中的int, double, char... 它也是在一種語言中最基本的類型,
與編譯器編譯出的代碼具有重大關系.
"新式類"和“經典類”的區分在python3中就已經不存在了,而在之後的版本裡,所有的類都派生出了自類置類型object,即所有的類都是新式類
經典類繼承算法是深度優先,新式類則是廣度優先
class A():#此代碼在2.7.14中運作,也可以在3.6.3中運作,但是許多大型的經典類執行個體,隻能在2.7中運作
var='classic class A'
class B(A):
pass
class C():
var='class C'
class sunclass(B,C):
if __name__=='__main__':
print(sunclass.var)
最後結果:classic class A
再來看新式類
class A(object):
var='classic class A'
pass
class C(A):
var='class C'
print(sunclass.var)
最後結果:class C
這恰好就是上節分享的深度優先和廣度優先
但是值得注意的是,新式類并非全部都是廣度優先,而是采用c3算法(這一部分以後繼續進行介紹)
可是為什麼python3之中,會出現新式類呢,經典類用的不是挺好的嗎,這個需要通過具體問題來進行分析
在經典類中所有的類都是classobj類型,而類的執行個體是instance類型,類與執行個體隻有通過__class__屬性進行關聯,這樣在判斷執行個體時,就會造成不便,所有的類都是instance類型
class A():pass#此代碼在python32.7中運作
class B():pass
a = A()
b = B()
if __name__ == '__main__':
print(type(a))
print(type(b))
print(type(a) == type(b))
最後結果
<type 'instance'>
True
type(a) == type(b)的結果永遠為True,那這樣的比較就毫無意義。
更為麻煩的是,經典類的執行個體是instance類型,而内置類的執行個體卻不是,無法統一。
但是在python3中卻沒有這樣的要求
同樣代碼,在python3中的運作結果
<class '__main__.A'>
<class '__main__.B'>
False
綜上:
Python3中所有的類都是新式類,新式類中類與類型已經統一:類執行個體的類型是這個執行個體所建立自的類(通常是和類執行個體的__class__相同),而不再是Python 2.x版本中的“instance”執行個體類型。
五星級:字段,屬性(重要)
字段分為,靜态字段和普通字段
靜态字段:屬于類
普通字段:屬于對象,
讓我們來通過一個小代碼,了解什麼是靜态字段,和普通字段
class Provinces:
#靜态字段
country='中國'
def __init__(self,name):
self.name=name#普通字段
#直接通路普通字段
obj=Provinces('河北省')
print(obj.name)
#直接通路靜态字段
print(Provinces.country)
靜态字段在記憶體中隻儲存一份
普通字段在每個對象中都要儲存一份
屬性:
屬性有兩個知識點:
1,屬性的基本使用
2,屬性的兩種定義方式
一:屬性的基本使用:
class Foo:
def func(self):
print('求魔')
#定義屬性
@property#定義屬性之前的必須操作
def pro(self):
return "wu pei qi"
foo_obj=Foo()
foo_obj.func()
c=foo_obj.pro
print(c)
屬性的定義和調用注意以下幾點:
1:定義時,在普通方法的基礎上調用@property方法
2:定義時,屬性中僅有一個self函數
3:調用時無需括号
foo_obj.func()
c=foo_obj.pro
屬性存在意義是:通路屬性時可以制造出和通路字段完全相同的假象
屬性由方法變種而來,如果Python中沒有屬性,方法完全可以代替其功能。
執行個體:對于主機清單頁面,每次請求不可能把資料庫中的所有内容都顯示到頁面上,而是通過分頁的功能局部顯示,是以在向資料庫中請求資料時就要顯示的指定擷取從第m條到第n條的所有資料(即:limit m,n),這個分頁的功能包括:
根據使用者請求的目前頁和總資料條數計算出 m 和 n
根據m 和 n 去資料庫中請求資料
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
def end(self):
val=self.current_page*self.per_items
p = Pager(1)
print(p.start)#就是起始值,即:m
print(p.end) #就是結束值,即:n
屬性的兩種定義方式
1,裝飾器 即:在方法上運用裝飾器
2,靜态字段 ,即在類中定義值為property對象的靜态字段
第一種裝飾器方式:(在類的普通方法上應用@property裝飾器)
(此處隻介紹新式類的方法)
#新式類:
class Goode(object):
def price(self):
print('@property')
@price.setter
def price(self, value):
print('@price.setter')
@price.deleter
print('@price deleter')
obj=Goode()
obj.price
obj.price=123
del obj.price # 自動執行 @price.deleter 修飾的 price 方法
新式類中的屬性有三種通路方式,并分别對應了三個被@property、@方法名.setter、@方法名.deleter修飾的方法
由于新式類中具有三種通路方式,我們可以根據他們幾個屬性的通路特點,分别将三個方法定義為對同一個屬性:擷取、修改、删除
def __init__(self):
#原價
self.original_price=100
#折扣
self.discount=0.8
#實際價格=原價*折扣
new_price=self.original_price*self.discount
return new_price
def price(self,value):
self.original_price=value
print('%s'%(value))
del self.original_price
print(obj.price)
obj.price=81
靜态字段方式,建立值為property對象的靜态字段
def get_bar(self):
return 'wupeiqi'
BAR=property(get_bar)
obj=Foo()
result=obj.BAR
print(result)
這是一個小執行個體
我們再來看一個蠻經典的執行個體
class Foo(object):
def __init__(self,name):
self.name=name
return self.name
def set_bar(self,value):
self.name=value
def del_bar(self):
del self.name
BAR=property(get_bar,set_bar,del_bar,'desadfas')
obj = Foo('100')
print(obj.BAR) # 自動調用第一個參數中定義的方法:get_bar
obj.BAR = "alex"#print(obj.)# 自動調用第二個參數中定義的方法:set_bar方法,并将“alex”當作參數傳入
print(obj.BAR)
del Foo.BAR # 自動調用第三個參數中定義的方法:del_bar方法,進行删除
class Goods(object):
self.origina_price=100
def get_price(self):
new_price=self.origina_price*self.discount
def set_price(self,value):
self.original_price = value
def del_price(self):
PRICE = property(get_price, set_price, del_price, '價格屬性描述...')
obj = Goods()
obj.PRICE # 擷取商品價格
obj.PRICE = 200 # 修改商品原價
del obj.PRICE # 删除商品原價
第三部分:靜态方法、類方法、屬性方法
1,靜态方法
簡單了解:通過@staticmethod裝飾器即可把其裝飾的一個方法轉變為靜态方法,但什麼是靜态方法,普通方法必須執行個體化之後才能調用,但是靜态方法,已經跟類本身沒有關系,它與類的為唯一關聯是需要通過類名才能調用這個方法
class Dog(object):
@staticmethod
def eat(self):
print("%s is eating"%self.name)
d=Dog("dsfas")
d.eat()
上述會出現一系列錯誤
因為當eat變成靜态方法後,再通過執行個體調用時就不會自動把執行個體本身當作一個參數傳給self了。
而要解決它的方式有兩種
一個是把d當成self傳入當中
另一個就是把self去掉
self.name = name
def eat():
print(" is eating")
d = Dog("ChenRonghua")
即可
2,類方法
類方法通過@classmethod裝飾器實作,類方法和普通方法的差別是, 類方法隻能通路類變量,不能通路執行個體變量
self.name=name
@classmethod
def eat(self):
print("%s is eating" %self.name)
d=Dog("chenronghua")
這段代碼,執行時會進行報錯
是以,我們需要定義一個類變量
name = "我是類變量"
def __init__(self, name):
self.name = name
print("%s is eating" % self.name)
3,屬性方法
剛才我們提到了屬性變量,其實屬性變量就是屬性方法
這次我們來做一個小案例
比如 ,你想知道一個航班目前的狀态,是到達了、延遲了、取消了、還是已經飛走了, 想知道這種狀态你必須經曆以下幾步:
1. 連接配接航空公司API查詢
2. 對查詢結果進行解析
3. 傳回結果給你的使用者
lass Flight(object):
self.flight_name=name
def checking_status(self):
#print('檢查飛機的運作狀态:'%self.flight_name)
return 1
@property
def flight_status(self):
status=self.checking_status()
if status==0:
print('飛機取消了')
elif status==1:
print('飛機飛行之中')
elif status==2:
print('飛機降落了')
else:
print("不能夠證明飛機的運作狀态")
@flight_status.setter
def flight_status(self,status):
status_dic={
0:"canceled",
1:"arrived",
2:"depatured"
}
print("\033[31;1m已經修改了飛行的狀态到 \033[0m", status_dic.get(status))
@flight_status.deleter
print("status got removed")
f=Flight("波音777")
f.flight_status
f.flight_status=2
好了,非常基礎的東西就講完了,我們來講一點比較偏門的,畢竟學習一門語言還要了解他的一些源代碼,知道是怎樣運作的,才能不斷精進
類的特殊成員用法:
1,__doc__:表示類的描述資訊:
在開發中,我們需要在代碼中多加注釋,來增強代碼的可讀性,用__doc__就可以檢視函數或類的描述資訊
def test():
'''
this is a test function
class ClassTest(object):
this is a class method
print(test.__doc__)
print(ClassTest.__doc__)
這個函數可以用來檢視注釋
2、__module__和__class__
__module__ 表示對象所在的子產品
__class__ 表示對象所在的類是什麼
3,__init__ 構造方法,通過類建立對象時,自動觸發執行
5. __call__ 對象後面加括号,觸發執行。
注:構造方法的執行是由建立對象觸發的,即:對象 = 類名() ;而對于 __call__ 方法的執行是由對象後加括号觸發的,即:對象() 或者 類()()
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('call')
obj()
6.__dict__ 檢視類或對象中的所有成員
class Province:
country='China'
def __init__(self,name,count):
self.count=count
def func(self,*args,**kwargs):
print('func')
print(Province.__dict__)#擷取類的成員,靜态字段,方法
obj1=Province('HeBei',10000)
print(obj1.__dict__)#擷取obj1的成員
<code>class</code> <code>Foo:</code>
<code> </code><code>def</code> <code>__str__(</code><code>self</code><code>):</code>
<code> </code><code>return</code> <code>'alex li'</code>
<code>obj </code><code>=</code> <code>Foo()</code>
<code>print</code> (<code>obj)</code>
<code># 輸出:alex li</code>
用于索引操作,如字典。以上分别表示擷取、設定、删除資料
def __getitem__(self, item):
print('__getitem',item)
def __setitem__(self, key, value):
print('__setitem__',key,value)
def __delitem__(self, key):
print('__delitem__',key)
result=obj['k1']
obj['k2']='alex'
del obj
最後一部分:
反射即想到4個内置函數分别為:getattr、hasattr、setattr、delattr 擷取成員、檢查成員、設定成員、删除成員
現對這幾個函數進行細緻的分享,
getattr(object, name[,default])
擷取對象object的屬性或者方法,如果存在即列印出來,如果不存在,即列印出預設值,預設值可選
需要注意的是,如果傳回的是對象的方法,傳回的是方法的記憶體位址,如果運作這個方法,可以在後面添加一對括号
class test():
name="xiaohua"
def run(self):
print( "helloworld")
t=test()
print(getattr(t,"name"))#擷取name屬性,存在就列印出來。
print(getattr(t, "run")) #擷取run方法,存在就列印出方法的記憶體位址。
getattr(t, "run")() #擷取run方法,後面加括号可以将這個方法運作。
print(getattr(t, "age","18")) #若屬性不存在,傳回一個預設值。
hasattr(object, name)
判斷一個對象裡面是否有name屬性或者name方法,傳回BOOL值,有name特性傳回True, 否則傳回False。需要注意的是name要用括号括起來
print(hasattr(t,"name"))#判斷對象有name屬性
print(hasattr(t, "run")) #判斷對象有run方法
setattr(object, name, values)
給對象的屬性指派,若屬性不存在,先建立再指派
print(hasattr(t,"age"))#判斷屬性是否存在
setattr(t, "age", "18") #為屬相指派,并沒有傳回值
print(hasattr(t, "age") ) #屬性存在了
綜合運用
self.name = 'wupeiqi'
def func(self):
return 'func'
obj = Foo()
#### 檢查是否含有成員 ####
print(hasattr(obj, 'name'))
print(hasattr(obj, 'func'))
#### 擷取成員 ####
getattr(obj, 'name')
getattr(obj, 'func')
#### 設定成員 ####
setattr(obj, 'age', 18)
setattr(obj, 'show', lambda num: num + 1)
#### 删除成員 ####
delattr(obj, 'name')
#delattr(obj, 'func')#不能用于删除方法,否則報錯
本文轉自眉間雪 51CTO部落格,原文連結:http://blog.51cto.com/13348847/1981001,如需轉載請自行聯系原作者