1. 程式人生 > >魔術方法1

魔術方法1

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