Python基礎:Python類(真累~)
一、類的屬性
(私有屬性和公有屬性)
(類屬性)
二、類的方法
(構造方法、析構方法、自定義方法、特殊成員方法)
(靜態方法、類方法、類屬性)
三、類的繼承
(方法和屬性的繼承,方法的重構)
(抽象類,多重繼承)
四、類的多態
(實現接口的重用)
五、類的特殊裝飾
(@staticmethod、@classmethod、@property)
六、類的來源和原類(metaclass)
七、反射
類的聲明
使用class聲明類,建議類名單詞首字母大寫。
“新式類”和“經典類”的區分在Python 3之後就已經不存在,在Python 3.x之後的版本,因為所有的類都派生自內置類型object(即使沒有顯示的繼承object類型),即所有的類都是“新式類”。
新式類:
class Management(object): def add(): pass
經典類:
class Management: pass
類的屬性
類的屬性就是類定義的變量值。
公有屬性:在類裏直接定義的屬性,它在類名下面直接定義。
調用:1、類中調用:類名.屬性名 ,更改原公有屬性值
2、實例調用:實例.屬性名
class Management(object): num = 10 def add(self): Management.num +=10 # 類中調用公有屬性並更改值,num=11 pass s1 = Management() s2 = Management() # 第一種情況:s1實例中調用公有屬性,s2實例沒有調用公有屬性 s1.num +=1 Management.num += 2 """ <結果> s1不變,s2和Management都改變了 s1_num:11 s2_num:12 Manage_num:12 """ # 第二種情況:先調用s1實例公有屬性,再通過S1調用add更改,然後再使用類更改 s1.num +=1 s1.add() Management.num += 2 """ <結果> 先調用的s1實例num依然不變,s2和Management都被修改了 s1_num:11 s2_num:22 Manage_num:22 """
問題:為什麽修改num的值以後,實例s1和實例s2會有不同的結果呢 ?
因為公有屬性查找的順序是:先找實例的公有屬性,沒找到再找類裏的公有屬性
可以這樣理解:Management相當於一個微信群,num是群裏發的一張照片,S1和S2是群裏面的兩個人。
情況1:S1把照片存到本地,P了個雙眼皮,S2說太難看了,我也不會P圖,不保存。這個時候發照片的Management說我也覺得難看,把圖撤回,重新發了一個P的圖。S2就只能保存最新的圖片。
情況2:S1找到Management說你的圖太醜了,重新改一下吧,Management說好!撤回圖片修改了~
私有屬性:加兩個下劃線,__membername,編譯的時候自動加上類名,變成_classname__membername,這種技術叫變量名壓縮(mangling),以達到外部不能調用的目的。實際使用_classname__membername是可以調用的,但是不符合規定。標準方法是通過定義函數來獲取。
class Classname(object): '''this is a demo!''' def __init__(self): self.__membername = 88 def read_membername(self): # 標準的外部訪問方法,使用函數來讀取私有屬性。 return self.__membername s= Classname() print(s._Classname__membername) print(s.read_membername()) ''' <結果> 88 88 ------像下面的調用,會出現AttributeError錯誤------ print(s.__membername) '''
類屬性: 類自帶的屬性,需要註意的是實例化的類屬性,和原類的類屬性不同。用上面的例子作演示。
屬性 | 作用 | 示例 | 結果 |
__doc__ | 類的文檔字符串 | print(s.__doc__) print(Classname.__doc__) | this is a demo! this is a demo! |
__dict__ | 類的屬性組成的字典 | print(s.__dict__) print(Classname.__dict__) | {'_Classname__membername': 88} {'__init__':, '__module__': '__main__', '__doc__': '\nthis is a demo!\n', 'read_membername':} |
__name__ | 類的名字(字符串) | ##不能用於實例print(s.__name__ ) print(Classname.__name__ ) | Classname |
__bases__ | 類的所有父類組成的元組 | #不能用於實例print(s.__bases__) print(Classname.__bases__) | (,)為什麽沒有值?可能是編譯器問題 |
__module__ | 類所屬的模塊 | print(s.__module__) print(Classname.__module__) | __main__ __main__ |
__class__ | 類對象的類型 | print(s.__class__) print(Classname.__class__) | 待測 |
__slots__ | 限定類屬性,在類屬性位置定義 未在slots定義的屬性都是非法屬性 | __slots__.('name','age','sexy') | 使用'name','age','sexy'的以外屬性會報錯 |
類的方法
類的方法就是類裏面定義的函數。類的構造方法、析構方法、自定義類方法、靜態方法、類方法、屬性方法、特殊成員方法。
構造方法:__init__
實例化類的時候就會運行的函數。希望初始化的參數放置在init下面。(個人覺得,這個初始化參數可以是一切對象!)
class A(object): def instense(self): print("init obj A") class B(object): def __init__(self, para): self.init_para = para self.obj_A = A() self.num = 1 def show(self): print(self.init_para) self.obj_A.instense() print(self.num) haha = B("this is para") haha.show() ---------- this is para init obj A 1
析構方法:
__del__:銷毀實例時,方法才會執行。
class Hello(object): def __del__(self): print("你刪除了實例") # 在python上測試 instance = Hello() del instance # 當然也可以使用實例調用,但沒有這麽用的~~ instance.__del__()
自定義方法:
除去類中自帶的以_下劃線開頭的函數,在類中定義一個函數,實現相應的功能。
class Person(object): def __init__(self,person_name, person_age)
靜態方法:
@staticmethod,不需要訪問類裏的任何參數。所帶的參數都是從外部傳入的。
class Person(object): def __init__(self,person_name, person_age): self.name = person_name self.age = person_age @staticmethod def info(country): print(country)
類方法:
@classmethod,第一個參數必須是類屬性。
class Person(object): country = "china" def __init__(self,person_name, person_age): self.name = person_name self.age = person_age @classmethod def info(country): print(country)
屬性方法:
@property把一個函數變成一個靜態屬性
直接調用函數名字,不需要加括號,就能獲取到函數返回值。一般用在不註重過程,只要結果的情況!
class Person(object): country = "china" def __init__(self,person_name, person_age): self.name = person_name self.age = person_age @property def health_point(self): print("HP:【{}】".format(self.age*2)) return self.age*2 P = Person("laowang",23) P.health_point # 不需要括號,看起來完全是一個屬性,這就是屬性方法
特殊成員方法:
方法 | 作用 | 示例 | 結果 |
__call__ | 默認未定義 類實例化後,調用實例運行的方法 | p = Person() p() | Person是類名 實例p沒有調用函數,加()運行call方法 |
__str__ | 默認未定義,定義時必須有返回值 定義時,打印實例,輸入str返回值 | p = Person() print (p) | Person是類名 打印實例p,運行str方法,打印返回值 |
__getitem__ | 用於索引操作,如字典。獲取數據 | p = Person() p['name'] | 自動運行getitem |
__setitem__ | 用於索引操作,如字典。賦值 | p = Person() p['name'] = 'David' | 自動運行setitem |
__delitem__ | 用於索引操作,如字典。刪除數據 | p = Person() del p['name'] | 自動運行delitem |
__new__ | 類實例化時,執行__new__,並且會阻止 init運行,可以在new裏調用init | p = Person() | 參照例子二 |
__len__ | 待續 | ||
__cmp__ | 待續 |
'''例子一call\str\getitem\setitem\delitem方法''' class Person(object): def __call__(self): print("print call") def __str__(self): print("print str:",end='') return "1" def __getitem__(self,key): print("getitem:",key) def __setitem__(self,key,value): print('setitem:',key,value) def __delitem__(self,key): print('delitem:',key) p = Person() p() print(p) print('-----------') get = p['name'] p['name'] = 'David' del p['name']
'''例子二:__new__/__init__''' class Person(object): def __init__(self): print('this is init!') def __new__(self): print("this is new!") self.__init__(self) # 如果去掉這一行,init不能執行 p = Person()
類的來源和元類:
http://blog.jobbole.com/21351/中文版詳細解答。下面寫一個自己理解的簡版的。
首先,類也是對象,可以:
1) 你可以將它賦值給一個變量
2) 你可以拷貝它
3) 你可以為它增加屬性
4) 你可以將它作為函數參數進行傳遞
類也是是由type()這個函數創建的,type是類的類,類的爹。學名叫元類!
也許有人會問那為啥type()能查看到數據類型呢?因為數據類型在Python中都是類定義的,這也說明了,為什麽數字,字符等等全是對象。
type格式:
type(類名,(父類元組),{屬性字典},{方法詞典}) , 父類元組可以沒有;後面兩個典省略時,默認值為None。
'''一言不合就上例子''' class Person(object): country = 'china' Person = type('Person',('object',),{'country':china})
未完待續。。。
類的繼承
類的多態
反射
Python基礎:Python類(真累~)