1. 程式人生 > >python中類中常見的特殊成員

python中類中常見的特殊成員

# 類的特殊成員
class gg:
    '''
    這裡都是特殊類成員方法,在觸發後這些方法都根據這些方法自動傳遞的引數就行程式碼的編寫
    '''
    #print(gg.__doc__)  # 檢視類的描述資訊
    def __init__(self,name):  #初始化物件  #類名() 建立物件的時候自動建立
        self.name = name
        self.data = {'key':'cisco'}#定義一個類中的字典

    def __call__(self, *args, **kwargs):  #觸發執行,使用  物件() 就會自動執行該方法的內容
print('call 觸發後執行這裡的程式碼') def __getitem__(self, item):# 使用物件['key'] 後自動呼叫, 會將'key' 的值傳到item print('隨你喜歡,你可以對傳遞過來的值任意蹂躪') return self.data[item] def __setitem__(self, key, value): #物件['key'] = 'value' 後會自動呼叫,像字典一樣傳值到對應的引數中 print(key,value ,'進行自由的程式碼操作的,拿到這兩個值之後可以隨便操作
') self.data[key] = value def __delitem__(self, key):# 像字典一樣,使用del 物件['key'] 會自動執行 print('我是%s,如果喜歡可以按照字典的方式對類的key進行刪除如下:'%key) del self.data[key] def __enter__(self): #使用with 物件 + as b 的時候 自動呼叫 print('進來了,自動執行後的隨意程式碼區,可以隨便編寫') def __exit__(self, exc_type, exc_val, exc_tb):#使用with 物件 + as b 的時候 自動呼叫
print('出去了,自動執行後的隨意程式碼區,可以隨便編寫') def __add__(self, other): # 兩個物件相加的的時候進行呼叫 print('自動執行後的隨意程式碼區,可以隨便編寫') def __str__(self): #在對應物件的時候呼叫並返回相應的return後面的 內容 通過列印呼叫 也可以使用str(物件) print('自動執行後的隨意程式碼區,可以隨便編寫') return '列印物件的時候就將這裡的內容進行返回' def __repr__(self): #轉化為解析器讀取的形式, 呼叫時repr(物件) pass def __hash__(self):#設定本物件的hash 的功能,如果直接在物件的後面新增__hash__ = None 的話,該物件不能被進行雜湊 return '可以給自己定義的物件設定可以hash的功能' def __new__(cls, *args, **kwargs):#構造方法__new__ 開闢記憶體,觸發 __init__建立例項 return object.__new__(cls) def __cmp__(self,x): #物件比較 呼叫方法 cmp(物件,x) pass def __del__(self): #析構方法:當物件在記憶體中被釋放時,自動觸發執行 del 物件 pass a = gg('panzhenwei') # 觸發__new__ __init__ print(gg.__module__) # 檢視當前操作的模組是哪個 print(gg.__class__) #檢視當前操作的類是哪個 print(gg.__dict__) # 檢視類或物件的成員,類只是列印類的成員不列印物件的成員 print(a.__dict__) # 檢視類或物件的成員,物件只對應物件的成員,不列印類的成員 print(a ) #觸發__str__ a() # 觸發__call__ a['name'] = 'cisco'# 觸發__setitem__ a['name'] # 觸發__getitem__ del a['name'] # 觸發__delitem with a as f: # 自動觸發__enter__ 和__exit__ print('列印這裡的時候已經觸發了__enter__') print('程式碼執行到這裡,說明已經退出了上面的控制代碼,已經觸發完__exit__') # 來自菜鳥程式設計的示例 class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self, other): return Vector(self.a + other.a, self.b + other.b) v1 = Vector(2, 10)# 觸發__new__ __init__ v2 = Vector(5, -2)# 觸發__new__ __init__ print(v1 + v2) # 觸發__add__, 觸發__new__ __init__ 觸發__str__ #結果 Vector(7,8) #這個是字串

 

 

init
構造方法,每個物件被例項化出來的時候都將首先去執行init方法

class A:
    def __init__(self): print("在建立物件的時候會首先自動執行__init__") 

del
析構方法,每個物件在被垃圾回收機制回收之前執行的方法

class A:
    def __del__(self): print("在物件銷燬之前會執行__del__")

doc
類的描述資訊

class A:
    """我是A類的描述資訊"""
    pass 

module
表示當前操作的物件在哪個模組

class A:
    """我是A類的描述資訊"""
    pass 
from lib import A
a = A()
print(a.__module__)

class
表示當前操作的物件的類是什麼

class A:
    pass

a = A()
print(a.__class__)

call
類名後面加括號表示建立一個物件;如果在物件後面加括號,就需要使用call方法了,如果不定義這個方法,在執行物件()的時候就會報錯

class A:

    def __call__(self, *args, **kwargs): print("call") a = A() a() ------------ call 

建立物件的時候首先執行init,在物件被呼叫的時候執行call

也可以在一行執行

a = A()()

str
print物件的時候顯示的內容

class A:
    pass

a = A()
print(a)

------------
<__main__.A object at 0x101b77128> 

在沒有定義str的情況下,輸出的是a物件的記憶體地址資訊

class A:
    def __str__(self): return "A~" a = A() print(a) ------------ A~ 

str的應用例項

class B:
    def __init__(self, name): self.name = name def __str__(self): return self.name b = B("ps") print(b) ------------ ps 

str型別轉換

class B:
    def __init__(self, name): self.name = name def __str__(self): return self.name b = B("ps") ret = str(b) print(ret) 

str(b)和print()都會自動去呼叫b物件中的str方法

dict
物件的dict
在物件中預設已經有dict,不需要自定義。該方法用來獲取物件中所有封裝的物件

class B:
    def __init__(self, name, age): self.name = name self.age = age def __str__(self): return self.name b = B("ps", 26) print(b.__dict__) ------------ {'age': 26, 'name': 'ps'} 

類的dict
列出類中所有可以呼叫的方法

class B:
    def __init__(self, name, age): self.name = name self.age = age def __str__(self): return self.name b = B("ps", 26) print(B.__dict__) ------------ {'__weakref__': <attribute '__weakref__' of 'B' objects>, '__module__': '__main__', '__str__': <function B.__str__ at 0x10137b730>, '__init__': <function B.__init__ at 0x10137b6a8>, '__doc__': None, '__dict__': <attribute '__dict__' of 'B' objects>} 

add
當執行一個物件 + 一個物件的時候,就會自動去執行這個方法

注意,執行的是第一個物件的add方法

class A:
    def __init__(self, num): self.num = num def __add__(self, other): return self.num + other.num class B: def __init__(self, num): self.num = num a = A(5) b = B(9) c = a + b print(c) 

getitem setitem delitem
用於索引操作,如字典。以上分別表示獲取、設定、刪除資料

d = {"k": "v"}
print(d["k"])
d["k"] = "vv" del d["k"] 

上面的程式碼展示了一個字典物件的取值、賦值和刪除的操作。在自定義的類中,也可以實現類似於字典這樣的操作
物件後面加小括號是執行call方法,那麼物件後面加中括號又是怎樣處理的呢?

使用key進行的操作
取值

class B:
    def __init__(self, name, age): self.name = name self.age = age def __str__(self): return self.name def __getitem__(self, item): print("執行了getitem方法", item) b = B("ps", 26) b["name"] ------------ 執行了getitem方法 name 

賦值

class B:
    def __init__(self, name, age): self.name = name self.age = age def __str__(self): return self.name def __getitem__(self, item): print("執行了getitem方法", item) def __setitem__(self, key, value): print("你要為%s重新賦值為%s" % (key, value)) b = B("ps", 26) print(b.name) b["name"] = "lr" ------------ ps 

你要為name重新賦值為lr
刪除

class B:
    def __init__(self, name, age): self.name = name self.age = age def __str__(self): return self.name def __getitem__(self, item): print("執行了getitem方法", item) def __setitem__(self, key, value): print("你要為%s重新賦值為%s" % (key, value)) def __delitem__(self, key): print("你要刪除%s" % key) b = B("ps", 26) del b["age"] ------------ 你要刪除age 

在web開發中,自定義session框架的時候會用到

使用下標進行的操作
使用下標和使用key的形式類似,使用key, item接收的是一個字串,使用下標, item接收的是一個int型別的數字,可以在方法體內通過判斷傳遞過來資料的資料型別來進行對應的操作

使用切片的操作

l = [1,2,3,4,5,6,7,8,9]
l[1:5:2]

在Python2.x中使用getslice setslice delslice來實現切片的操作,但是Python3.x中被遺棄,所有切片的功能都集中在了getitem setitem delitem

class B:
    def __init__(self, name, age): self.name = name self.age = age def __str__(self): return self.name def __getitem__(self, item): # print("執行了getitem方法", item) print(type(item)) def __setitem__(self, key, value): print("你要為%s重新賦值為%s" % (key, value)) def __delitem__(self, key): print("你要刪除%s" % key) b = B("ps", 26) b["name"] b[1] b[1:5:2] ------------ <class 'str'> <class 'int'> <class 'slice'> 

item為slice時表示呼叫了切片的操作

class B:
    def __init__(self, name, age): self.name = name self.age = age def __str__(self): return self.name def __getitem__(self, item): print("起點索引", item.start) print("終點索引", item.stop) print("步長", item.step) return "haha" def __setitem__(self, key, value): print("你要為%s重新賦值為%s" % (key, value)) def __delitem__(self, key): print("你要刪除%s" % key) b = B("ps", 26) ret = b[1:5:2] print(ret) ------------ 起點索引 1 終點索引 5 步長 2 haha 

相對應的,取值可以通過判斷item的型別做相應的操作,賦值和刪除也可以通過判斷key的型別來進行想對應的切片操作

class B:
    def __init__(self, name, age): self.name = name self.age = age def __str__(self): return self.name def __getitem__(self, item): print("起點索引", item.start) print("終點索引", item.stop) print("步長", item.step) return "haha" def __setitem__(self, key, value): print("起點索引", key.start) print("終點索引", key.stop) print("步長", key.step) print("新值為", value) def __delitem__(self, key): print("起點索引", key.start) print("終點索引", key.stop) print("步長", key.step) b = B("ps", 26) print("切片取值") ret = b[1:5:2] print("切片賦值") b[1:5:2] = "hehe" print("切片刪除") print(ret) del b[1:5:2] ------------ 切片取值 起點索引 1 終點索引 5 步長 2 切片賦值 起點索引 1 終點索引 5 步長 2 新值為 hehe 切片刪除 haha 起點索引 1 終點索引 5 步長 2 

iter
一個自定義類例項化的物件,預設是不可迭代的,在類中使用iter方法後,物件就變成了可迭代物件。當物件被迭代時,會自動呼叫iter方法

class A:
    pass

a = A()
for i in a: print(i) ------------ Traceback (most recent call last): File "/Users/lvrui/PycharmProjects/untitled/8/c8.py", line 5, in <module> for i in a: TypeError: 'A' object is not iterable 
class A:
    def __iter__(self): return iter([1, 2]) # return了一個可迭代物件 a = A() for i in a: print(i) ------------ 1 2

class A:
    def __iter__(self): # 返回了一個生成器 yield 1 yield 2 a = A() for i in a: print(i) ------------ 1 2 

先去a物件中找到iter方法執行,並拿到返回值進行迭代

new metaclass

class A(object):
 
    def __init__(self): pass a = A() # a是通過A類例項化的物件 

上述程式碼中,a 是通過 A 類例項化的物件,其實,不僅 a 是一個物件,A類本身也是一個物件,因為在Python中一切事物都是物件。

如果按照一切事物都是物件的理論:a物件是通過執行A類的構造方法建立,那麼A類物件應該也是通過執行某個類的構造方法建立。

print type(a) # 輸出:<class '__main__.A'>     表示,a物件由A類建立
print type(A) # 輸出:<type 'type'> 表示,A類物件由type類建立 

所以,a物件是A類的一個例項,A類物件是type類的一個例項,即:A類物件是通過type類的構造方法建立

那麼,建立類就可以有兩種方式:

  • 普通方式
class A(object):
 
    def func(self): print("ps") 
  • 特殊方式(type類的建構函式)
def func(self):
    print("ps") A = type('A',(object,), {'func': func}) #type第一個引數:類名 #type第二個引數:當前類的基類 #type第三個引數:類的成員 

–> 類是由type類例項化產生

那麼問題來了,類預設是由 type 類例項化產生,type類中如何實現的建立類?類又是如何建立物件?

答:類中有一個屬性metaclass 其用來表示該類由誰來例項化建立,所以,我們可以為metaclass設定一個type類的派生類,從而檢視類建立的過程:

  類建立的過程

 

class MyType(type):

    def __init__(self, what, bases=None, dict=None): super(MyType, self).__init__(what, bases, dict) def __call__(self, *args, **kwargs): obj = self.__new__(self, *args, **kwargs) self.__init__(obj) class A(object): __metaclass__ = MyType def __init__(self, name): self.name = name def __new__(cls, *args, **kwargs): return object.__new__(cls, *args, **kwargs) # 第一階段:直譯器從上到下執行程式碼建立A類 # 第二階段:通過A類建立a物件 a = A()