• 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.描述器

     

    本文为原创文章,转载请标明出处
  • 相关阅读:
    (总结)Nginx配置文件nginx.conf中文详解(转自:http://www.ha97.com/5194.html)
    位图数据压缩算法
    sqlalchemy 使用
    Linux c 使用数学函数库出现问题.
    小笔记
    hibernate框架的学习(一)
    foreach
    发现的问题
    第一天练习
    进制转换
  • 原文地址:https://www.cnblogs.com/harden13/p/9027193.html
Copyright © 2020-2023  润新知