美文网首页
Python 进阶之魔术方法

Python 进阶之魔术方法

作者: 不会忘的名字 | 来源:发表于2019-01-09 20:50 被阅读0次

    Python魔术方法

    __开头,__结尾的方法就是魔术方法.

    • 1.__str__格式化输出对象
      __repr__表示对象本身
    class A:
        def __str__(self):
            return 'This is A'
        
        # 表示对象本身
        def __repr__(self):
            return "I'm a A"
    
    a = A()
    print(a)  # This is A
    a  # I'm a A
    
    • 2.__init____new__

    __init__ 初始化实例,无返回值
    __new__创建一个实例,并返回类的实例.
    __new__是一个特殊的类方法,不需要使用@classmethod来装饰.

    使用__new__单例模式

    # 借助__new__方法实现单例模式
    class Singleton:
        instance = None
        
        def __new__(cls, *args, **kwargs):
            # 判断实例对象是否已经存在
            if cls.instance is None:
                # 说明实例对象不存在.需要创建
                cls.instance = super().__new__(Singleton, *args, **kwargs)
            return cls.instance  
    
    s = Singleton()
    s2 = Singleton()
    s is s2
    out: True
    display(id(s), id(s2))
    out: 78960288  78960288
    
    • 3.数学运算、比较运算
      运算符重载

    +:__add__(value)
    -: __sub__(value) substract
    *: __mul__(value) mulply
    /: __truediv__(value) (Python 3.x), __div__(value) (Python 2.x) divide
    //: __floordiv__(value)
    %: __mod__(value)
    &: __and__(value)
    |:__or__(value)

    # 自定义字典的加法
    class Dict(dict):
        # 实现加法
        def __add__(self, other):
            # 判断other是否是字典.
            if isinstance(other, dict):
                new_dict = {}
                new_dict.update(self)
                new_dict.update(other)
                return new_dict
            else:
                raise TypeError('not a dict')
    
    d1 = {1: 11, 2: 22}
    d2 = {1: 111, 2: 222, 3:333}
    dd1 = Dict(d1)
    dd1 + d2
    out:{1: 111, 2: 222, 3: 333}
    
    # 定义一个类,长方形  , 让长方形类的实例对象可以实现减法操作.
    class Rectangle:
        def __init__(self, height, width):
            self.height = height
            self.width = width
            
        # 实现减法
        def __sub__(self, other):
            if isinstance(other, Rectangle):
                return Rectangle(abs(self.height - other.height), abs(self.width - other.width))
            else:
                raise TypeError('not a rectangle')
                
        def __repr__(self):
            return  f'<Rectangle ({self.height}, {self.width})>'
    
    r1 = Rectangle(1,2)
    r2 = Rectangle(1,1)
    r1 - r2
    out:<Rectangle (0, 1)>
    

    比较运算符的重载

    ==: __eq__(value)
    !=: __ne__(value)
    >: __gt__(value)
    >=: __ge__(value)
    <: __lt__(value)
    <=: __le__(value)

    # 定一个类实现数学上的无穷大
    class Inf:
        def __eq__(self, other):
            return False
        
        def __ne__(self, other):
            return True
        
        def __gt__(self, other): 
            return True
        
        def __ge__(self, other):
            return False
        
        def __lt__(self, other):
            return False
        
        def __le__(self, other):
            return False
    
    inf = Inf()
    inf > 20 ** 10000
    out:True
    
    # 练习: 写个长方体, 让长方体的实例对象之间可以比体积大小.
    # 优化版本
    class Cuboid:
        def __init__(self, lenght, width, height):
            self.lenght = lenght
            self.width = width
            self.height = height
            
        @property
        def V(self):
            return self.lenght * self.width * self.height
        
        def __gt__(self, other):
            if isinstance(other, Cuboid):
                return self.V > other.V
            else:
                raise TypeError('not a cuboid')
                
        def __repr__(self):
            return f'<Cuboid  ({self.lenght}, {self.width}, {self.height}>'
    
    c1 = Cuboid(2,3,4)
    c2 = Cuboid(1,1,1)
    c1 > c2
    out:True
    sorted([c1,c2])  # 对体积进行排序
    out:[<Cuboid  (1, 1, 1>, <Cuboid  (2, 3, 4>]
    
    • 4.容器方法

    __len__ -> len
    __iter__ -> for
    __contains__ -> in
    __getitem__ 对 string, bytes, list, tuple, dict 有效
    __setitem__ 对 list, dict 有效
    __missing__ 对 dict 有效, 字典的预留接口, dict 本身并没有实现

    l = [1,2,3]
    len(l)
    out:3
    l.__len__()
    out:3
    
    l[0]
    out: 1
    l.__getitem__(0)
    out: 1
    
    l[0] = 8
    l
    out:[8, 2, 3]
    l.__setitem__(0,10)
    l
    out: [10, 2, 3]
    
    d1 = {1: 111, 2: 222, 3: 333}
    d1[0]
    out:---------------------------------------------------------------------------
    KeyError                                  Traceback (most recent call last)
    <ipython-input-77-f64ff61913e8> in <module>()
    ----> 1 d1[0]
    KeyError: 0
    
    # 让字典的key找不到的时候,不要报错.返回空列表
    class Dict(dict):
        def __missing__(self, key):
            return []
    ddd = Dict(d1)
    ddd[0]
    out: []
    
    • 5.上下文管理 with:

    __enter__进入 with 代码块前的准备操作
    __exit__ 退出时的善后操作
    文件对象、线程锁、socket 对象 等 都可以使用 with 操作
    with 不管with语句块中是否出现异常,资源依然可以被正常的释放.

    exceptions = []
    class A:
        def __enter__(self):
            print('enter....')
            print(self)
            return self
        
        def __exit__(self, Error, error, Exception):
            print(Error, error, Exception)
            exceptions.append(Error)
            exceptions.append(error)
            exceptions.append(Exception)
            print('exiting....')
    
    with A() as a:
        print(a)
        print('------------------')
        raise TypeError() 
    
    out:enter....
    <__main__.A object at 0x0000000004E44940>
    <__main__.A object at 0x0000000004E44940>
    ------------------
    <class 'TypeError'>  <traceback object at 0x0000000004DD9848>
    exiting....
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-111-421bdf2504b3> in <module>()
          2     print(a)
          3     print('------------------')
    ----> 4     raise TypeError()
          5 
    TypeError: 
    
    exceptions
    out:[TypeError, TypeError(), <traceback at 0x4dd9848>]
    Error, error, trace = exceptions
    import traceback
    traceback.print_exception(Error, error, trace)  # 打印出异常
    
    out:Traceback (most recent call last):
      File "<ipython-input-111-421bdf2504b3>", line 4, in <module>
        raise TypeError()
    TypeError
    

    python的内省

    setattr() # 设置属性__setattr__()
    getattr() # 获取属性__getattribute__
    hasattr() # 判断是否有某个属性

    class A:
        def __init__(self,  x, y):
            self.x = x
            self.y = y
    a = A(1,2)
    
    setattr(a, 'z', 3)
    a.z
    out: 3
    a.__setattr__('z', 9)
    a.z
    out: 9
    
    getattr(a, 'x')
    out: 1
    a.__getattribute__('x')
    out: 1
    # __getattr__当__getattribute__找不到属性的时候,会执行__getattr__
    
    # 默认获取不到会报错
    getattr(a, 'a', 0)
    out: 0
    
    hasattr(a, 'a') 
    out: False
    'a' in a.__dict__
    out: False  # 没有a.__hasattr__('a')
    
    # 常用于属性监听
    class User:
        '''TestClass'''
        z = [7,8,9]
        def __init__(self):
            self.money = 10000
            self.y = 'abc'
    
        def __setattr__(self, name, value):
            if name == 'money' and value < 0:
                raise ValueError('money < 0')
            print('set %s to %s' % (name, value))
            object.__setattr__(self, name, value)
    
        def __getattribute__(self, name):
            print('get %s' % name)
            return object.__getattribute__(self, name)
    
        def __getattr__(self, name):
            print('not has %s' % name)
            return -1
    
        def foo(self, x, y):
            return x ** y
    
    # 对比
    a = User()
    # print(User.__dict__)
    # print(a.__dict__)
    out: set money to 10000
    set y to abc
    
    a.money -= 11000  #  = a.money = a.money - 11000
    out: get money
    ---------------------------------------------------------------------------
    ValueError  
    ---> 11             raise ValueError('money < 0')
         12         print('set %s to %s' % (name, value))
         13         object.__setattr__(self, name, value)
    ValueError: money < 0
    
    • 8.槽: __slots__

    固定类所具有的属性
    实例不会分配 __dict__
    实例无法动态添加属性
    优化内存分配, 大概能节约40%的内存.

    class B:
        __slots__ = ['x', 'y']
    
    b = B()
    b.x = 10
    b.x
    out: 10
    
    b.z = 10
    out: ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-147-47de4eac37de> in <module>()
    ----> 1 b.z = 10
    AttributeError: 'B' object has no attribute 'z'
    
    b.__dict__  # 报错没有__dict__
    out:---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-148-395029f23f31> in <module>()
    ----> 1 b.__dict__
    AttributeError: 'B' object has no attribute '__dict__'
    

    相关文章

      网友评论

          本文标题:Python 进阶之魔术方法

          本文链接:https://www.haomeiwen.com/subject/phtirqtx.html