魔術方法1
阿新 • • 發佈:2017-11-19
delta context except nonetype 減法 brush pass reduce attr_
# 特殊屬性: __name__ 類、方法等名字 __module__ 類定義所在的模塊名 __class__ 對象或類所屬的類 __bases__ 類的基類的元組,順序為它們在基類列表出現的順序 __doc__ 類、方法的文檔字符串,沒有定義默認為None __mro__ 類的moro,class.mro()返回的結果保存在__mro__中 __dict__ 類或實例的屬性,可寫的字典 # 查看屬性: __dir__: 返回類或者對象的所有成員名稱列表。dir()函數就是調用__dir__()。如果提供 __dir__(),則返回屬性的列表,否則會盡量從__dict__屬性中收集信息。 如果dir([obj])參數包含方法__dir__(),該方法將被調用。如果參數不包含__dir__(),該方法將最大限度地收集參數信息 dir()對於不同類型的對象具有不同的行為: 如果對象是模塊對象,列表包含模塊的屬性名。 如果對象是類型或者類對象,列表包含類的屬性名,及它的基類的屬性名 否則列表包含對象的屬性名,它的類的屬性名和類的基類的屬性名。 ```python class Foo: def __init__(self, name, age): self.name = name self.age = age def show(self): return self.age x = Foo(‘z‘,12) x.show() print(Foo.__name__) def fn(x): return fn(x-1)+fn(x-2) fn(5) ``` Foo --------------------------------------------------------------------------- RecursionError Traceback (most recent call last) <ipython-input-6-121340e7e479> in <module>() 11 def fn(x): 12 return fn(x-1)+fn(x-2) ---> 13 fn(5) <ipython-input-6-121340e7e479> in fn(x) 10 11 def fn(x): ---> 12 return fn(x-1)+fn(x-2) 13 fn(5) ... last 1 frames repeated, from the frame below ... <ipython-input-6-121340e7e479> in fn(x) 10 11 def fn(x): ---> 12 return fn(x-1)+fn(x-2) 13 fn(5) RecursionError: maximum recursion depth exceeded # 魔術方法: 分類: 1.創建與銷毀 __init__ 與 __del__ 2.hash 3.bool 4.可視化 5.運算符重載 6.容器和大小 7.可調用對象 8.上下文管理 9.反射 10.描述器 11.其他 ```python """ 1.__hash__ 內建函數hash()調用的返回值,返回一個整數,如果定義這個方法該類的實例就可hash """ class A: def __init__(self): self.a = ‘a‘ self.b = ‘b‘ def __hash__(self): return 1 def __eq__(self, other): return self.a == other.a print(hash(A())) print((A(),A())) print({A(),A()}) s = {A(),A()} print(s) ``` 1 (<__main__.A object at 0x000001A2B6A2BD30>, <__main__.A object at 0x000001A2B6A2BAC8>) {<__main__.A object at 0x000001A2B6A2BB38>} {<__main__.A object at 0x000001A2B6A2BD30>} # \__eq\__ __eq__ 對應==操作符,判斷2個對象是否相等,返回bool值 __hash__方法返回一個hash值作為set的key,但是去重,還需要__eq__來判斷2個對象 是否相等 hash值相等,只是hash沖突,不能說明兩個對象是相等的。 一般提供__hash__方法是為了作為set或者dict的key的,所以去重 要同時提供__eq__方法 可hash對象必須提供__hash__方法,沒有提供的話,isinstance(p1,collections.Hashable) 一定為false __hash__方法返回一個hash值作為set的key,但是去重,還需要__eq__來判斷2個對象 是否相等 hash值相等,只是hash沖突,不能說明兩個對象是相等的。 一般提供__hash__方法是為了作為set或者dict的key的,所以去重 要同時提供__eq__方法 可hash對象必須提供__hash__方法,沒有提供的話,isinstance(p1,collections.Hashable) 一定為false # list類不可hash: 在list類源碼中,有一句__hash__ = None,也就是如果調用__hash__()相當於None() 一定報錯,。 所有類都繼承object,而這個類是具有__hash__()方法 ,如果一個類不能被hash,就是 把__hash__設置為None了。 ```python from collections import Hashable class Point: def __init__(self, x ,y): self.x = x self.y = y def __hash__(self): return hash((self.x, self.y)) def __eq__(self, other): return self.x == other.x and self.y == other.y p1 = Point(4,5) p2 = Point(4,5) print(hash(p1)) print(hash(p2)) print(p1 is p2) print(p1 == p2)c print(set((p1, p2))) print(isinstance(p1, Hashable)) ``` 3713084879518070856 3713084879518070856 False True {<__main__.Point object at 0x000001A2B6AE3898>} True # bool __bool__ 內建函數,或者對象放在邏輯表達式的位置,調用這個函數返回布爾值, 沒有定義__bool__(),就找__len__()返回長度,非0為真。如果__len__()也沒有定義,那麽所有實例返回真 ```python class A: pass print(bool(A())) class B: def __bool__(self): return False print(bool(B))#類 print(bool((B())))#實例 class C: def __len__(self): return 0 print(bool(C())) ``` True True False False # 可視化 __repr__ 內建函數rer()對一個對象獲取字符串表達。如果一個類定義了__repr__()但沒有定義__str__,那麽在請求該類的實例的‘非正式‘的字符串也將調用__repr__() __str__ str()函數,內建函數format、print()函數調用,需要返回對象的字符串表達 __bytes__ bytes的時候,返回一個對象的bytes表達,即返回Bytes對象 ```python class A: def __init__(self): self.a = ‘a‘ self.b = ‘b‘ def __repr__(self): return ‘repr: {}, {}‘.format(self.a, self.b) def __str__(self): return ‘str: {}, {}‘.format(self.a, self.b) print(A()) print([A()]) print(([str(A())])) print(‘str:a,b‘) s = ‘b‘ print([‘a‘], (s,)) ``` str: a, b [repr: a, b] [‘str: a, b‘] str:a,b [‘a‘] (‘b‘,) # 運算符重載 ```python ‘實例的減法‘ class A: def __init__(self, x): self.x = x def __sub__(self, other):#減法 return self.x - other.x def __ne__(self, other): return self.x != other.x def __eq__(self, other): return self.x == other.x a1 = A(4) a2 = A(4) a1-a2 # 等價於 a1.__sub__(a2) print(a1 == a2) print(a1 != a2) ``` True False ```python class Point: """ __sub__ 相等 __add__ 相加 __str__ 格式化字符串 """ def __init__(self, x, y): self.x = x self.y = y def __eq__(self, other): return self.x == self.x and self.y == self.y def __add__(self, other): return (self.x + other.x, self.y + other.y ) def __str__(self): return (self.x and self.y) a = Point(3,5) b = Point(1,2) print(a+b) ``` (4, 7) ```python ‘購物車類改造成方便操作的容器‘ class Cart: def __init__(self): self.items = [] def __len(self): return len(self.items) def additem(self, item): self.items.append(item) def __iter__(self): return iter(self.items) def __getitem__(self, item): return self.items[item] def __setitem__(self, key, value): self.items[key] = value cart = Cart() cart.additem(1) ``` # 可調用對象: 在python中,一切皆對象 函數也是 __call__ 實例可以像函數一樣被調用 ```python def foo(x): print(x) foo(5) print(foo.__dict__) print(foo.__call__(5)) print(dir(foo)) ``` 5 {} 5 None [‘__annotations__‘, ‘__call__‘, ‘__class__‘, ‘__closure__‘, ‘__code__‘, ‘__defaults__‘, ‘__delattr__‘, ‘__dict__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__get__‘, ‘__getattribute__‘, ‘__globals__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__kwdefaults__‘, ‘__le__‘, ‘__lt__‘, ‘__module__‘, ‘__name__‘, ‘__ne__‘, ‘__new__‘, ‘__qualname__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘] ```python class A: def __call__(self, *args, **kwargs): print(5 A()() # a = A() a() ``` 5 ```python class Point: def __init__(self, x, y): self.x = x self.y = y def __call__(self, *args, **kwargs): return "" ``` ```python class Fib: def __init__(self): self.numlst = [0,1] def fib_iter(self, value): for i in range(value - 2): self.numlst.append(self.numlst[-2] + self.numlst[-1]) return self.numlst x = Fib() x.fib_iter(10) ``` ```python class Fib: """ f(n-1) + f(n-2) """ def __init__(self): self.lst = [0,1] def fib_iter(self, values): ret = 0 for i in range(values - 2): self.lst.append(self.lst[-2] + self.lst[-1]) return self.lst f = Fib() f.fib_iter(9) ``` [0, 1, 1, 2, 3, 5, 8, 13, 21] ```python class Fib: """ f(n-1) + f(n-2) """ def __init__(self): self.lst = [0,1,1] def __call__(self, value): if value < len(self.lst): # 返回對象的長度減少計算量 return self.lst for i in range(len(self.lst),value): self.lst.append(self.lst[i-1] + self.lst[i-2]) return self.lst def __getitem__(self,index):#取索引 a[x] = xx if index < 0: return None if index < len(self.lst): return self.lst[index] else: self(index) def __iter__(self): return iter(self.lst) #可以叠代 fib = Fib() fib(20) for i in fib: print(i) ``` 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 # 上下文管理: __enter__ 進入與此對象(實例)相關的上下文。如果存在該方法,with語法會把該方法的值作為綁定到as子句中指定的變量上 __exit__ 退出與此對象相關的上下文 實例化對象的時候,不會調用enter,進入with語句塊調用enter方法,然後執行語句體,最後離開with語句塊的時候。調用exit方法 with可以開啟一個上下文運行環境,在執行前做一些準備工作,執行後做一些收尾工作 上下文應用場景: 1、增強功能 在代碼執行的前後增加代碼,以增強其功能,類似裝飾器 2、資源管理 打開了資源需要關閉,例如文件對象,網絡連接,數據庫連接等 3、權限驗證 在執行代碼之前,做權限的驗證,在__enter__中處理 ```python class Point: """ __enter__ 進去做的事情 __exit__ 退出做的事情 """ def __init__(self): print(‘init‘) def __enter__(self): print(self.__class__) return self def __exit__(self, exc_type, exc_val, exc_tb): print(self.__class__.__name__) print(exc_type)#異常類型 print(exc_val)#異常的值 print(exc_tb)#異常的追蹤信息 return 0#返回一個等效的值 True壓制 False拋出異常 p = Point() with p as f: raise Exception(‘Error-zz‘) print(f == p)#enter如果沒有返回值 就為False print(f is p) print(‘outer‘) ``` init <class ‘__main__.Point‘> Point <class ‘Exception‘> Error-zz <traceback object at 0x0000019117DA9C48> --------------------------------------------------------------------------- Exception Traceback (most recent call last) <ipython-input-227-cf8294135f8a> in <module>() 18 p = Point() 19 with p as f: ---> 20 raise Exception(‘Error-zz‘) 21 print(f == p)#enter如果沒有返回值 就為False 22 print(f is p) Exception: Error-zz ```python import datetime import time def times(fn): def wrapper(*args, **kwargs): start = datetime.datetime.now() print(args, kwargs) ret = fn(*args,**kwargs) after = datetime.datetime.now() - start return ret return wrapper @times def add(x, y): time.sleep(2) return x + y print(add(2,y=4)) ``` (2,) {‘y‘: 4} 6 ```python import time import datetime from functools import wraps class TimeIt: def __init__(self, fn): self._fn = fn def __enter__(self): print(‘enter‘) self.start = datetime.datetime.now() return self def __call__(self, *args, **kwargs): print(‘call‘) start = datetime.datetime.now() print(args, kwargs) ret = self._fn(*args, **kwargs) delta = datetime.datetime.now() - start print(‘took{} s‘.format(delta)) return ret #return self.fn(*args, **kwargs) def __exit__(self, exc_type, exc_val, exc_tb): delta = (datetime.datetime.now() - self.start).total_seconds() print(‘exit‘) print(delta) return # def times(fn): # @wraps(fn) # def wrapper(*args, **kwargs): # start = datetime.datetime.now() # print(args, kwargs) # ret = fn(*args,**kwargs) # after = datetime.datetime.now() - start # return ret # return wrapper # @times @TimeIt# add = TimeIt(add) def add(x, y): time.sleep(2) return x + y add(3,4) # with TimeIt(add) as foo: # print(foo(5,3)) ``` call (3, 4) {} took0:00:02.000684 s --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-299-034e034cf759> in <module>() 42 return x + y 43 add(3,4) ---> 44 add.__doc__() 45 # with TimeIt(add) as foo: 46 # print(foo(5,3)) TypeError: ‘NoneType‘ object is not callable # Contextlib.contextmanager 它是一個裝飾器實現上下文管理,裝飾一個函數,不用像類一樣實現__enter__和__exit__方法。 對下面的函數有要求,必須有yield,也就是這個函數必定返回一個生成器,且只有yield一個值。 ```python import contextlib @contextlib.contextmanager def foo(): print(‘enter‘)# 相當於 __enter__() yield 5 #作為__enter__方法的返回值 print(‘exit‘)#相當於__exit__() with foo() as f: print(f) ‘f接收yield語句的返回值‘ ``` enter 5 exit ‘f接收yield語句的返回值‘ ```python import contextlib @contextlib.contextmanager def foo(): print(‘enter‘) try: yield 5 finally: print(‘exit‘) with foo() as f: raise Exception() print(f) #執行yield,為生成器函數增加了上下文管理 ``` enter exit --------------------------------------------------------------------------- Exception Traceback (most recent call last) <ipython-input-6-cddb091c6a6e> in <module>() 10 print(‘exit‘) 11 with foo() as f: ---> 12 raise Exception() 13 print(f) Exception: ```python import contextlib import datetime import time @contextlib.contextmanager def add(x, y): start = datetime.datetime.now() try: yield x + y finally: delta = (datetime.datetime.now()- start).total_seconds() print(delta) with add(4,5) as f: time.sleep(3) print(f) ‘如果業務邏輯簡單可以使用函數加裝飾器方式,如果業務復雜,用類的方式加__enter__和__exit__方法方便。‘ ``` 9 3.000015 ‘如果業務邏輯簡單可以使用函數加裝飾器方式,如果業務復雜,用類的方式加__enter__和__exit__方法方便。‘
魔術方法1