zoukankan      html  css  js  c++  java
  • Python 面向对象(三) 魔术方法

    __getitem__   在对实例或对象使用索引访问时调用,self[key]
    __dir__     收集当前模块的信息,包括继承自其它基类(包括object类)的属性和方法
    __new      定义如何创建实例
    __init__      构造方法,实例创建时如何初始化
    __del__      析构方法,对象在内存中被释放时,自动触发执行
    __file__        当前文件在系统中的绝对路径
    __hash__     hash值相同表示hash冲突,但并不代表对象值相同。列表不可hash,元组可hash。
              内建类型集合(set)的源码中就用到了"__hash__ = None",来表示set是不可hash类型。
              hash()等同于调用__hash__()方法
            isinstance(1,hashable) 是否可hash
    __equal__    == 判断是否相等
          a == b 等价于
          a.__equal__(b)
    __bool__      返回bool()布尔值,__bool__() --> __len__() 搜索顺序。
          如果没有__bool__(),则调用__len__()返回长度,非0就为真。
           如果__len__也没有定义,则所有实例都为真


    可视化相关的魔术方法:
    __repr__    重写表现形式,__str__ --> __repr__ --> object 查找顺序。至少有个__repr__
    __str__      format(),print(),str()函数调用时使用的方法,如果没有__str__,则调用__repr__方法,所以这两个方法尽量写一样。
    __bytes__      在对象使用bytes()函数时调用此方法
    __ascii__

    ——————————————————————————————————————

    运算符重载

    容器
    __len__     元素个数,必须大于等于0
            size有可能是容器的大小
    __iter__     迭代容器时调用,返回一个新的迭代器对象
    __contains__   in成员运算符 __contains__ --> __iter__顺序
    __getitem__   返回self[key] 的值,不存在返回KeyError异常
    __setitem__
    __missing__   调用__getitem__时,key不存在时触发,以免抛异常


    链式编程

    深入学习综合症

    __repr__ = __str__

    ——————————————————————————————————————————————

    运算符重载,+= 举例:

    class A:
        def __init__(self,x):
            self.x = x
        def __repr__(self):
            return str(self.x)
        def __iadd__(self, other):
            # return A(self.x + other.x) #生成新对象
            self.x = self.x + other.x  #就地修改
            return self
    
    a1 = A(4)
    a2 = A(10)
    a3 = A(5)
    print(id(a1),id(a2),id(a3))
    a1 += a2
    print(id(a1),a1)
    ~~~~~~
    4362338144 4362338200 4362338256
    4362338144 14   #对比可以看到前后的id(a1)内存地址一致,为就地修改
    

      上面例子是就地修改,下面这个例子是生成新对象,对比id(a1)内存地址。

    class A:
        def __init__(self,x):
            self.x = x
        def __repr__(self):
            return str(self.x)
        def __iadd__(self, other):
            return A(self.x + other.x) #生成新对象
            # self.x = self.x + other.x  #就地修改
            # return self
    
    a1 = A(4)
    a2 = A(10)
    a3 = A(5)
    print(id(a1),id(a2),id(a3))
    a1 += a2
    print(id(a1),a1)
    ~~~~~~~~~~~~~~~~~~
    4362338088 4362338144 4362338200
    4362604616 14  #id(a1)值不等,生成的是新对象
    

      

    练习:
    设计二维坐标类Point,使其成为可hash类型,并比较2个坐标的实例是否相等。
    class Point:
        def __init__(self,x,y):
            self.x = x
            self.y = y
        def __str__(self):
            return '{},{}'.format(self.x,self.y)
        def __eq__(self, other):
            return (self.x == other.x) and (self.y == other.y)
        def __iadd__(self, other):
            return Point((self.x + other.x),(self.y + other.y))
    
    p1 = Point(4,5)
    p2 = Point(6,5)
    
    print(p1 == p2)
    p1 += p2
    print(p1)
    

      

    练习:
    购物车支持索引的方式检索商品:
    class Color:
        RED = 0
        BLACK = 1
        WHITE = 2
        BLUE = 3
    
    class Item:
        def __init__(self,**kwargs):
            self.spec = kwargs
        def __repr__(self):
            return str(sorted(self.spec.items()))
        def __str__(self):
            return str(sorted(self.spec.items()))
        def __getitem__(self, item):
            return self.spec.items()[item]
    
    
    class Cart:
        def __init__(self):
            self.items = []
        def addItems(self,item):
            self.items.append(item)
        def getAllItems(self):
            return self.items
        def __add__(self, other):   # +
            pass
        def __len__(self):
            return len(self.getAllItems())
        def __iter__(self):
            return iter(self.items)
            # for item in self.getAllItems():
            #     yield item
        def __getitem__(self, index): #index
            return self.items[index]
        def __missing__(self, key):  #只支持字典
            print(key)
        def __setitem__(self, key, value): #索引不可以超界
            self.items[key] = value
            return self.items
    
    mycart = Cart()
    mycar = Item(mark='tesla',color=Color.WHITE,price='100w',speed='400km/h',year=2017)
    myphone = Item(mark='Nokia',color=Color.BLACK,price=5000,memory='4G')
    mymac = Item(mark='MacPro',color=Color.WHITE,price=19999,memory='16G',ssd='512G')
    mycart.addItems(mycar)
    mycart.addItems(myphone)
    mycart.addItems(mymac)
    for item in mycart.getAllItems():
    # for item in mycart:
        print(item.__dict__)
    print(mycart.__len__())
    print(mycart[2])
    

      

    练习:斐波那契数列支持索引方式查找第n个数字。索引和调用两种方式:
    class Fib:
        """0,1,1,2,3,5,8,13,21"""
    
        def __init__(self):
            self.lst = []
    
        def __call__(self, n, *args, **kwargs):
            i = 0
            prev, next = 0, 1
            while True:
                self.lst.append(prev)
                if i == n:
                    return prev
                prev, next = next, prev + next
                i += 1
    
        def __getitem__(self, item):
            return self.__call__(item)
    
    f1 = Fib()
    # print(f1(7))
    # print(f1(8))
    print(f1[8])
    

      

    回顾下普通装饰器
    import datetime
    import time
    
    
    def timer(fn):
        def wrapper(x, y):
            start = datetime.datetime.now()
            print('start:',start)
            print(fn(x, y))
            time.sleep(1)
            stop = datetime.datetime.now()
            # print('stop: ',stop)
            return 'stop:  {}'.format(stop)
    
        return wrapper
    
    
    @timer
    def add(x, y):
        return x + y
    
    
    num1 = add(3, 4)
    print(num1)
    

      

    上下文管理
    	类作为上下文,进入上下文时如果有定义__enter__方法,则做该方法的动作。
    	__enter__  进去了帮我做某事,
    	__exit__	离开时候帮忙
    				必须同时存在
    					import sys
    					sys.exit() 强制退出脚本
    				异常退出时处理
    	exc_type
    	exc_val
    	exc_tb  traceback
    
    
    
    类装饰器
    	两个装饰器同时装饰
    	with TimeIt() as f:
    		pass
    
    	from functools import wrapås
    	@wraps(fn)
    	def self()....
    
    	==
    
    	wraps(fn)(self)  复制所有属性
    		类装饰是调用到__init__ 和__call__
    	--——————————————————————————————————————————————
    	
    	————————————————————————————————————————————————
    

      

    用类做装饰器,调用的是__enter__和__exit__:
    import datetime
    import time
    
    
    class TimeIt:
        def __init__(self, fn):
            print('__init__...')
            self.fn = fn
    
        def __enter__(self):
            self.start = datetime.datetime.now()
            print('Enter:', self.start)
            return self
    
        def __call__(self, *args, **kwargs):
            print('__call__....')
            self.start = datetime.datetime.now()
            print('Enter:', self.start)
            print(self.fn(*args, **kwargs))
            self.stop = datetime.datetime.now()
            # print('Exit:', self.stop)
            return 'Exit:  {}'.format(self.stop)
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.stop = datetime.datetime.now()
            print('Exit:', self.stop)
            return self
    
    
    @TimeIt
    def add(x, y):
        time.sleep(1)
        return x + y
    
    
    # with TimeIt(add) as foo:
    #     print(foo(3,4))
    
    print(add(3, 4))
    

      

    使用wraps的方式,拷贝所有属性:
    import time
    import datetime
    from functools import wraps
    
    class TimeIt:
    
        def __init__(self, fn):
            # self.__doc__ = fn.__doc__
            print('init')
            self._fn = fn
            wraps(fn)(self)
            #@wraps(fn) 等同于
            #def self()......
    
    
        def __enter__(self):
            print('enter')
            self.start = datetime.datetime.now()
            return self
    
        def __call__(self, *args, **kwargs):
            print('__call__')
            start = datetime.datetime.now()
            ret = self._fn(*args, **kwargs)
            delta = (datetime.datetime.now() - start).total_seconds()
            print("dec {} took {}".format(self._fn.__name__, delta))
            return ret
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('exit')
            delta = (datetime.datetime.now() - self.start).total_seconds()
            print("context {} took {}".format(self._fn.__name__, delta))
            return
    
    # def logger(fn):
    #     @wraps(fn)
    #     def wrapper(*args, **kwargs):
    #         start = datetime.datetime.now()
    #         ret = fn(*args, **kwargs)
    #         delta = (datetime.datetime.now() - start).total_seconds()
    #         print("dec {} took {}".format(fn.__name__, delta))
    #         return ret
    #     return wrapper
    
    @TimeIt
    def add(x,y): # add = TimeIt(add)
        """This is a add function.~~~~~~~~~~~~~~~"""
        time.sleep(2)
        return x + y
    
    print(add(10,11))
    
    print(add.__doc__)
    print(add.__name__)
    
    print(add.__dict__)
    # with TimeIt(add) as foo:
    #     print(foo(5, 16))
    

      

  • 相关阅读:
    HDU 4348 To the moon(可持久化线段树)
    HDU 5875 Function 大连网络赛 线段树
    HDU 5877 2016大连网络赛 Weak Pair(树状数组,线段树,动态开点,启发式合并,可持久化线段树)
    HDU 5876 大连网络赛 Sparse Graph
    HDU 5701 中位数计数 百度之星初赛
    CodeForces 708B Recover the String
    Java实现 蓝桥杯 算法提高 套正方形(暴力)
    ASP.NET生成验证码
    ASP.NET生成验证码
    ASP.NET生成验证码
  • 原文地址:https://www.cnblogs.com/i-honey/p/7844553.html
Copyright © 2011-2022 走看看