Python魔术方法

分类:

1.创建,初始化与销毁 __init__.__del__

类实例化调用__init__;当运行结束,.del 标识符,引用计数为0的时候调用__del__

2.hash

1.内建函数hash()调用的返回值,返回一个整数,如果定义这个方法该类的实例可hash;
2.hash是为了提供set,dict的key,hash可以冲突,冲突的时候用__eq__比较内容,实现去重
3.类一般都是可以hash,由于继承基类的属性,但是没有事项__hash__,我们认为不可以hash
4.list bytearray 内部用 __hash__ = None 实现不可以hash
class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y
    
    def __hash__(self):  #return 就是一个元祖,想要返回对象 Point(self.x,self,y)
        return hash((self.x,self.y))
    
    def __eq__(self,other):  #运算符重载 p1 == p2,判断对象是否相等,返回bool
        return (self.x,self.y) == (other.x,other.y)
#     return self.x ==other.x and self.y == other.y
def __repr__(self): return 'Point.x={},Point.y={}'.format(self.x,self.y)

3.bool

1.内建函数bool(),或者对象放在逻辑表达式的位置,调用这个函数返回bool,没有定义__bool__(),就找__len__()的长度,非0为真,如果__len__()也没有定义,所有实例都返回真
class A:
    def __len__(self):
        return 100
    __hash__ = None
if A():
    print("real a")
bool(A)
bool(A())

4.可视化

1.__repr__内建函数repr()对一个对象获取字符串表达,调用魔术方法返回字符串表达,如果没有定义,就直接返回object的定义就式显示内存的地址信息
2.__str__,str()函数,内建函数format(),print()函数调用,需要返回对象的字符串表达,如果没有定义,就去调用__repr__方法返回字符串表达,如果__repr__也没有定义,就直接返回对象的内存地址信息
3.__bytes__,bytes()函数调用,返回一个对象的bytes表达,返回bytes对象

5.运算符重载

1.比较运算符:lt,le,eq,gt,ge,ne -->[<, <=, == ,> ,>= ,!=]
2.算数运算符:add,sub,mul,truediv,mod,floordiv,pow,divmod -->[+-*/% // ** divmod]
3.iadd,isub,imul,itruediv,imod,ifloordiv,ipow --> [+=,-=,*=,/=,%=,//=,**=]
class Point:
    def __init__(self,x,y):
        self.x = x 
        self.y = y
    
    def __sub__(self,other):
        return Point(self.x-other.x,self.y-other.y)
    
    def __add__(self,other):
        return Point(self.x+other.x,self.y+other.y)
    
    def __repr__(self):
        return '<Point.x {},Point.y>'.format(self.x,self.y)

6.容器和大小

1.__len__:内建函数len(),返回对象长度,
2.__iter__:迭代容器的时候,调用,返回一个新的迭代对象(没有这个方法是instance(cart,Iterable)返回false,当for i in cart:调用__iter__)
3.__contains__:in成员运算符,没有实现就掉用__iter__方法遍历
4.__getitem__:实现self[key]访问,序列对象,key接受整数位索引,或者切片,对于set,dict,key为hashable,key不存在引发保存,索引访问
5.__setitem__:是设置值的方法,索引赋值
6.__missing__:字典或其子类使用__getitem__调用时,key不存在执行该方法
class Cart:
    def __init__(self):
        self.items = []

    def add(self,value):
        self.items.append(value)

    def __len__(self):
        return len(self.items)

    def __iter__(self):
        return iter(self.items)
     #yield from self.items
def __getitem__(self, item): return self.items[item] def __setitem__(self, key, value): self.items[key] = value def __str__(self): return str(self.items) def __add__(self, other): self.items.append(other) return self cart = Cart() print(cart) cart.add(1) cart.add(2) cart.add(3) print(cart+4+5+6) #链式变成实现加法
print(cart.__add__(17).__add__(18)

7.可调用对象

 

1.Pyhon一切皆对象,函数也不例外
2.__call__:类中定义一个该方法,实例就可以像函数一样调用
3.可调用对象:定义一个类,并实例化得到其实例,将实例像函数一样调用
4.要实现类实例的函数调用可以把函数调用写在__call__()内
5.可调用对象可以实现类装饰器; 见下面例子 
class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y
    def __call__(self,*args,**kwargs):
        return "<Point {}:{}>".format(self.x,self.y)
p = Point(4,5)
p()
class Adder:
    def __call__(self,*args):
        ret = 0
        for x in args:
            ret+=x
        self.ret = ret
        return ret
p =Adder()
p(10,10)
p.ret

 斐波数列用可调用方式并包装成容器实现

class Fib:
    def __init__(self):
        self.item=[0,1,1]
    def __call__(self,num):
        if num<len(self.item):
            return self.item[num]
        for i in range(len(self.item),num+1):
            self.item.append(self.item[i-1]+self.item[i-2])
        return self.item
    def __iter__(self):
        return iter(self.item)
    
    def __len__(self):
        return len(self.item)
    
    def __getitem__(self,key):
        return self.item[key]
    
fib = Fib()
for i in fib:
    print(i)
len(fib)
fib[2]
class Fib:
    def __init__(self):
        self.item=[0,1,1]
    def __call__(self,num):#num为形参,fib()先调用call,return在调用getitem魔术方法
        return self[num]
    def __iter__(self):
        return iter(self.item)
    def __len__(self):
        return len(self.item)
    def __getitem__(self,num): #这个num为实参,后调用getitem
        if num<len(self.item):
            return self.item[num]
        for i in range(len(self.item),num+1):
            self.item.append(self.item[i-1]+self.item[i-2])
#         return self.item[num]
    def __str__(self):
        return str(self.item)
    __repr__=__str__
   
fib = Fib()
fib(5)
print(fib(5))
import time
from datetime import datetime
from functools import wraps,update_wrapper
class Timeie:
    """this is Timeit"""
    def __init__(self,fn):
        self.fn = fn
        #update_wrapper(self,fn) 
        wraps(fn)(self) # wrapper = wraps(fn)(wrapper)
    def __call__(self,x,y):
        self.start=datetime.now()
        ret = self.fn(x,y)
        delta = (datetime.now()-self.start).total_seconds()
        print(delta)
        return ret
@Timeie #add = Timeit(add)
def add(x,y):
    """this is add"""
    time.sleep(2)
    return x+y
add(4,5)

8.上下文管理

1.当一个对象同时实现了__enter__()和__exit__()方法,它就属于上下文管理的对象
2.__enter__:进入与次相关的上下文,如果存在该方法,with语法就会把该方法返回
 __enter__方法返回值就是上下文中使用的对象,with语法会把他的返回值赋值给as子句的变量
3.__exit__:退出与此对象相关的上下文;方法返回一个等效的True值,压制异常,否则继续抛出异常
4.应用场景:增强功能,资源管理,权限验证(在执行代码前,做权限验证,在__enter__中处理)
5.contextlib库,@contextlib.contextmanager ;用来装饰函数,函数必须返回生成器,只有一个yield值;增加try保证exit执行
try:
  yield 5 #yield之前当作enter,之后当作exit,;yield值当作enter返回值
finally:
  print('exit')
class Point:
    def __init__(self):
        print('init')
    def __enter__(self):
        print('enter')
     return self  
def __exit__(self, exc_type, exc_val, exc_tb): print('exit') with Point() as f: #output init-->enter-->f-->exit print('f') 实例化对象的时候,并不会调用enter,进入with语句块的时候调用_enter__方法,然后执行语句体,
最后离开with语句快的时候调用__exit__方法,如果with语句块发生异常,enter,exit照样执行,上下文管理最安全
class Point:
    def __init__(self):
        print('init')
    def __enter__(self):
        print('enter')
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')
        print(exc_type,exc_val,exc_tb)
        return 0
p = Point()
with p as f:  #output init-->enter-->f-->exit
    raise Exception("new erroe")
    print('f')
import time
from datetime import datetime
def add(x,y):
    time.sleep(2)
    return x+y

class Timeit:
    def __init__(self,fn):
        self.fn = fn
def __enter__(self):
        self.start=datetime.now()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        delta = (datetime.now()-self.start).total_seconds()
        print(delta)
    def __call__(self,x,y):
        return self.fn(x,y)
p = Timeit(add)
print(p) #<__main__.Timeit object at 0x05100810>
print(Timeit(add)) #<__main__.Timeit object at 0x05219750>
with p as f: #with Timeit(add) as f ;print-->false print(p==f) f(5,6)

9.反射:动态增加属性

1.getattr(object,name,default) 通过name返回object的属性值,当属性值不存在的时候,将使用default返回,如果没有default,抛出异常,name必须为字符串
2.setattr(object,name,value) object的属性存在,则覆盖,不存在新增
3.hasattr(object,name) 判断对象是否有这个名字的属性,name必须为字符串
class Dispatcher:
    def __init__(self):
        self.run()
    def cmd1(self):
        print('i am cmd1')
    def cmd2(self):
        print("i am cmd2")
    def run(self):
        while True:
            cmd = input('please input a command').strip()
            if cmd == 'quit':
                break
            getattr(self,cmd,lambda:print('unkown{}'.format(cmd)))()
1.__getattr__():一般属性会按照继承关系找,如果找不到,就会执行__getattr__()方法,没有抛错
2.__setattr__():实例通过.设置属性,如同self.x = x 就会调用__setattr__(),属性要加到__dict__就要自己完成
3.__delattr__():可以阻止通过实例删除属性的操作,但是通过类依然可以删除属性
4.__getattribute__():实例的所有属性访问都会调用__getattribute方法,它阻止了属性的查找,该方法应该返回计算后的值,或者抛出个异常;return的值作为属性的查找结果,如果抛错,调用__getattr__表示属性没有找到
class Base:
    n = 0
class Point(Base):
    z = 6
    def __init__(self,x,y):
        print('init')
        self.x = x
        print('init2')
        self.y = y
    def show(self):
        print(self.x,self.y)
    def __getattr__(self,item):
        setattr(self,item,0)
#         getattr(self,item)产生递归
#         return 'missing {}'.format(item)
    def __setattr__(self,key,value):  #self.x 就会调用这个函数,如果不操作__dict__,就是空字典
        print('setattr')
        print("setattr {}={}".format(key,value))
        self.__dict__[key] = value
#         setattr(self,key,value)产生递归
#         getattr(self,key,value)产生递归
    def __delattr__(self,item):
        print('can not del {}'.format(item))
p1 = Point(3,4)
p1.__dict__
p1.aa=100 #aa:100
p1.t #t:0
del p1.x #output can not del x 
del Point.z#删除类的属性
class Base:
    n = 0
class Point(Base):
    z = 6
    def __init__(self,x,y):
        print('init')
        self.x = x
        self.y = y
    def __getattr__(self,item):
        return 'missing{}'.format(item)
    def __getattribute__(self,item):#所有实例的随性都从调用这个函数开始
        print('getattribute')
        return object.__getattribute__(self,item)

属性实例查找顺序:

实例调用__getattribute__()-->instance.__dict__-->instance.__class__.__dict__-->继承德祖先类直到object-->调用__getattr__()

10.描述器

 

posted @ 2018-05-12 00:45  亚洲哈登  阅读(256)  评论(0编辑  收藏  举报