• Python魔术方法


    参考python3.7官方文档

    基本方法

    __class__

    __name__

    __name__

    1)当前模块名,直接运行的模块的__name__为’__main__‘,其他的模块为’模块名’或’包名.模块名’

    # tmpPkg.tmp.py
    
    print(f'tmp.py {__name__}')
    
    
    
    # main.py
    
    import tmpPkg.tmp
    
    print(f'main.py {__name__}')
    
    
    
    > python .\main.py
    tmp.py tmpPkg.tmp
    main.py __main__
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2)对象类名 或 函数名

    class TestC:
        pass
    
    
    def testM():
        pass
    
    
    print(type(TestC()))
    print(TestC().__class__)
    # 
    # 
    
    print(type(TestC()).__name__)
    print(TestC().__class__.__name__)
    # TestC
    # TestC
    
    print(testM.__name__)
    # testM
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    __call__(self[, args…])

    class Test:
        def __call__(self, __x, __y):
            return f'{__x} + {__y} = {__x + __y}'
    
    
    t = Test()
    print(t(3, 5))
    # 3 + 5 = 8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    __new__(cls[, ])

    __del__(self)

    __init__(self[, ])

    __del__(self)

    __del__(self)

    new 创建对象,静态方法(此处特殊,不用标记@staticmethod)
    *new方法需要返回cls的一个实例,一般写作:return super().new(cls, *args, *kwargs),否则__init__函数将不会执行)
    init 初始化对象,同样注意调用父类的__init__方法
    del销毁对象(不推荐使用):当引用数为0销毁对象时调用,若父类包含del方法注意调用父类的del方法(object类无del方法)

    执行顺序:代码块 new方法 init方法 … del方法

    class Test:
        print('执行代码块')
    
        def __new__(cls, *args, **kwargs):
            print('执行new')
            return super().__new__(cls, *args, **kwargs)
    
        def __init__(self):
            print('执行init')
            super(Test, self).__init__()
    
        def __del__(self):
            print('执行del')
            # 若父类包含del方法注意调用父类的del方法(object类无del方法),故此处不调用
            # super(Test, self).__del__()
    
    
    Test()
    # 执行代码块
    # 执行new
    # 执行init
    # 执行del
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    __repr__(self)

    __str__(self)

    __str__(self)

    __repr__:描述对象的’正式字符串’,通常用于调试,因此表示信息丰富且明确。
    __str__:描述对象的’非正式字符串’,通常打印,因此表示信息简介方便。若__str__未实现但__repr__实现,则__str__将使用__repr__返回的字符串

    class Test:
        def __repr__(self):
            return 'aaa'
    
        def __str__(self):
            return 'bbb'
    
    
    t = Test()
    
    
    print(repr(t))
    print(str(t))
    print(t)
    # 未实现__repr__,未实现__str__
    # <__main__.Test object at 0x000002056CEEF588>
    # <__main__.Test object at 0x000002056CEEF588>
    # <__main__.Test object at 0x000002056CEEF588>
    
    # 实现__repr__,未实现__str__
    # aaa
    # aaa
    # aaa
    
    # 未实现__repr__,实现__str__
    # <__main__.Test object at 0x00000228D90B8608>
    # bbb
    # bbb
    
    # 实现__repr__,实现__str__
    # aaa
    # bbb
    # bbb
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    __bytes__(self)

    __bool__(self)

    __bool__(self)

    __bytes__:将对象转为bytes,通过bytes(x)调用
    __bool__:返回True/False,若__bool__未实现,则调用__len__方法,故[](空列表)、()(空元组)、‘’(或"",空字符串)、{}(空集合或空字典)的值均为False,除此之外的已经定义好的假值有False(标准真值)、None、0。

    class Test:
        def __bytes__(self):
            return b'x01x02'
    
        def __bool__(self):
            return True
    
    
    # 实现__bytes__
    t = Test()
    print(bytes(t))
    # b'x01x02'
    print(bool(t))
    # True
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    __fspath__(self)

    返回对象所在文件系统的路径str

    import os
    
    
    class Test:
        def __fspath__(self):
            return 'home/malloclu/TestObject'
    
    
    print(os.fspath(Test()))
    # home/malloclu/TestObject
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    (浅)复制与深复制

    已存在类型

    copy(浅)复制、deepcopy深复制

    from copy import copy, deepcopy
    
    # 基本数据类型
    a = 1.2
    
    # 1. 引用
    b1 = a
    # 2. (浅)复制
    b2 = copy(a)
    # 3. 深复制
    b3 = deepcopy(a)
    
    a = 3.4
    
    # 由于基本数据类型只有赋值没有引用,所以 3种方法 值均没有发生变化
    print(f'{b1}\n{b2}\n{b3}\n')
    # 1.2
    # 1.2
    # 1.2
    
    
    # 简单对象(例如单层容器)
    a = [1, 2, 3]
    
    # 1. 引用
    b1 = a
    # 2. (浅)复制
    b2 = copy(a)
    # 3. 深复制
    b3 = deepcopy(a)
    
    a[1] = 4
    
    # 仅 引用 方法值发生了变化,因为它和a指向的是内存中同一个对象
    print(f'{b1}\n{b2}\n{b3}\n')
    # [1, 4, 3]
    # [1, 2, 3]
    # [1, 2, 3]
    
    
    # 多层容器(例如多层容器,字典嵌套列表)
    a = {'k': [1, 2, 3]}
    
    # 1. 引用
    b1 = a
    # 2. (浅)复制
    b2 = copy(a)
    # 3. 深复制
    b3 = deepcopy(a)
    
    a['k'][1] = 4
    
    # 引用b1 和 (浅)复制b2 值发生了变化。其中b1因为和a指向的是内存中同一个对象,b2是因为浅复制生成的字典key引用到了a的[1, 2, 3]上,而b3因为深复制生成的字典key引用到了新生成的[1, 2, 3]上。
    print(f'{b1}\n{b2}\n{b3}\n')
    # {'k': [1, 4, 3]}
    # {'k': [1, 4, 3]}
    # {'k': [1, 2, 3]}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    memo

    memo字典中保留了内存id到对象的对应关系,以便完美地重构复杂的对象图。(若不想获知该对应关系,则使用deepcopy(x, memo={})时该参数可以不使用)

    from copy import deepcopy
    
    a = {'k': [1, 2, 3]}
    memo={}
    b = deepcopy(a, memo=memo)
    print(memo)
    # {2092202719048: [1, 2, 3], 
    # 2092195593896: {'k': [1, 2, 3]}, 
    # 2092195593976: [[1, 2, 3], {'k': [1, 2, 3]}]}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    自定义类型

    (浅)复制和深复制要分别实现__copy__(self)__deepcopy__(self, memodict={})方法

    from copy import copy, deepcopy
    
    
    class Test:
        def __init__(self, val):
            self.val = val
    
        def __copy__(self):
            return Test(self.val)
    
        def __deepcopy__(self, memodict={}):
            return Test(deepcopy(self.val, memodict))
    
        def __str__(self):
            return str(self.val)
    
    
    # 简单对象(例如单层容器)
    a = Test([1, 2, 3])
    
    # 1. 引用
    b1 = a
    # 2. (浅)复制
    b2 = copy(a)
    # 3. 深复制
    b3 = deepcopy(a)
    
    a.val[1] = 4
    
    # 引用b1 和 (浅)复制b2 值发生了变化。其中b1因为其和a指向的是内存中同一个对象,b2因为b2.val和a.val指向的是内存中同一个对象,而b3因为b3.val指向新生成的[1, 2, 3]。
    print(f'{b1}\n{b2}\n{b3}\n')
    # [1, 4, 3]
    # [1, 4, 3]
    # [1, 2, 3]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    运算符重载

    二元运算符

    方法列表

    符号运算反运算增量赋值运算(例如+=-=等)备注
    +__add__(self, other)__iadd__(self, other)__radd__(self, other)
    -__sub__(self, other)__isub__(self, other)__rsub__(self, other)
    *__mul__(self, other)__imul__(self, other)__rmul__(self, other)
    @__matmul__(self, other)__imatmul__(self, other)__rmatmul__(self, other)numpy类型实现了该方法,即矩阵乘法,基本数据类型和list未实现
    /__truediv__(self, other)__itruediv__(self, other)__rtruediv__(self, other)除以
    //__floordiv__(self, other)__ifloordiv__(self, other)__rfloordiv__(self, other)整除以
    %__mod__(self, other)__imod__(self, other)__rmod__(self, other)
    divmod(__x, __y)__divmod__(self, other)__rdivmod__(self, other)返回(商, 余数)
    **__pow__(self, other[, modulo])__ipow__(self, other[, modulo])__rpow__(self, other[, modulo])self的other次方 或 self的other次方对modulo取余
    <<__lshift__(self, other)__ilshift__(self, other)__rlshift__(self, other)左移
    >>__rshift__(self, other)__irshift__(self, other)__rrshift__(self, other)右移
    &__and__(self, other)__iand__(self, other)__rand__(self, other)按位与
    ^__xor__(self, other)__ixor__(self, other)__rxor__(self, other)按位异或
    ``__or__(self, other)__ior__(self, other)__ror__(self, other)
    <__lt__(self, other)
    <=__le__(self, other)
    ==__eq__(self, other)
    !=__ne__(self, other)
    >__gt__(self, other)
    >=__ge__(self, other)

    运算&反运算

    以+为例,A + B,要求 A重载了__add__运算符 或 B重载了__radd__运算符 (若均重载,则使用A的__add__运算符)【代码1】

    在重载的运算符方法中,应该对另一个操作数的类型进行判断,没有针对该类型编写代码时手动抛出异常【代码2】
    (例如A+B,A属于classA,B属于classB,A重载了__add__方法。当执行A+C(C属于classC)也能调用A的__add__方法,但A的__add__函数体是针对classB编写的,所以很可能执行失败出现各种异常情况。故推荐在A的__add__函数体中先判断另一个操作数的类型,针对不同的类型编写不同的操作,没有被考虑到的类型手动抛出异常)

    class TestA:
        def __add__(self, other):
            return f'add TestA + {type(other).__name__}'
    
    
    class TestB:
        pass
    
    
    class TestC:
        def __radd__(self, other):
            return f'radd {type(other).__name__} + TestC'
    
    
    # 左操作数重载了__add__,将被调用,对右操作的重载情况无要求
    print(TestA() + TestA())
    print(TestA() + TestB())
    print(TestA() + TestC())
    print(TestA() + 1)
    # add TestA + TestA
    # add TestA + TestB
    # add TestA + TestC
    # add TestA + int
    
    # 左操作数未重载__add__,若右操作重载__radd__将被调用,否则将报错
    print(TestB() + TestA())
    print(TestB() + TestB())
    print(TestB() + TestC())
    print(TestB() + 1)
    # TypeError: unsupported operand type(s) for +: 'TestB' and 'TestA'
    # TypeError: unsupported operand type(s) for +: 'TestB' and 'TestB'
    # radd TestB + TestC
    # TypeError: unsupported operand type(s) for +: 'TestB' and 'int'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    # 不推荐
    class TestA:
        def __add__(self, other):
            if isinstance(other, int):
                return f'add TestA + {type(other).__name__}'
    
    
    print(TestA() + 1)
    print(TestA() + 'tmp')
    # add TestA + int
    # None
    
    
    # **推荐**
    class TestB:
        def __add__(self, other):
            if isinstance(other, int):
                return f'add TestA + {type(other).__name__}'
            raise TypeError(f"unsupported operand type(s) for +: 'TestA' and '{type(other).__name__}'")
    
    
    print(TestB() + 1)
    print(TestB() + 'tmp')
    # add TestA + int
    # TypeError: unsupported operand type(s) for +: 'TestA' and 'str'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    增量赋值运算

    class TestA:
        def __init__(self, val):
            self.val = val
    
        def __add__(self, other):
            if isinstance(other, TestA):
                return TestA(self.val + other.val)
            raise TypeError(f"unsupported operand type(s) for +: 'TestA' and '{type(other).__name__}'")
    
    
    A = TestA(1)
    B = TestA(2)
    C = A + B
    print(C.val)
    
    
    class TestB:
        def __init__(self, val):
            self.val = val
    
        def __iadd__(self, other):
            if isinstance(other, TestB):
                return TestB(self.val + other.val)
            raise TypeError(f"unsupported operand type(s) for +: 'TestB' and '{type(other).__name__}'")
    
    
    A = TestB(4)
    B = TestB(5)
    A += B
    print(A.val)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    一元运算符

    方法列表

    符号方法备注
    -__neg__(self)取正,返回类型任意
    +__pos__(self)取负,返回类型任意
    abs(__x)__abs__(self)绝对值,返回类型任意
    ~__invert__(self)按位取反,返回类型任意
    complex(__x)__complex__(self)转换为复数,返回复数类型例如1+2j
    int()__int__(self)转换为整数,返回整数类型例如3
    float()__float__(self)转换为浮点数,返回浮点数类型例如4.5
    自动调用__index__(self)在需要整数的位置自动调用该函数将对象转换为整数类型,例如作为列表切片的索引时。
    round(__x, ndigits=0)__round__(self[, ndigits])就近取整,返回类型任意。已经实现的int类型结果为10^(-ndigits)的整数倍(ndigits默认为0,结果默认为1的整数倍即取整),round(0.5)为0,round(0.50001)为1。
    math.trunc(__x)__trunc__(self)截断取整,返回类型任意。已经实现的int类型math.trunc(-2.3)为-2。
    math.floor(__x)__floor__(self)向下取整,返回类型任意。已经实现的int类型math.floor(-2.3)为-3。
    math.ceil(__x)__ceil__(self)向上取整,返回类型任意。已经实现的int类型math.ceil(-2.7)为-2。

    示例

    import math
    
    
    class Test:
        def __neg__(self):
            return 'a'
    
        def __pos__(self):
            return 'b'
    
        def __abs__(self):
            return 'c'
    
        def __invert__(self):
            return 'd'
    
        def __complex__(self):
            return 1 + 2j
    
        def __int__(self):
            return 3
    
        def __float__(self):
            return 4.5
    
        def __index__(self):
            return 1
    
        def __round__(self, n=None):
            return 'e'
    
        def __trunc__(self):
            return 'f'
    
        def __floor__(self):
            return 'g'
    
        def __ceil__(self):
            return 'h'
    
    
    
    print(-Test())
    print(+Test())
    print(abs(Test()))
    print(~Test())
    # a
    # b
    # c
    # d
    
    print(complex(Test()))
    print(int(Test()))
    print(float(Test()))
    # (1+2j)
    # 3
    # 4.5
    
    testlist = ['aa', 'bb', 'cc']
    print(testlist[Test()])
    print(testlist[Test():Test()])
    # bb
    # []
    
    print(round(Test()))
    print(math.trunc(Test()))
    print(math.floor(Test()))
    print(math.ceil(Test()))
    # e
    # f
    # g
    # h
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    迭代器

    详细查看该csdn

    __next__返回迭代器对象的下一个值(如果没有抛出StopIteration异常),实现了该方法则该对象可以作为next(__x)的参数不断返回下一个值
    __iter__返回一个迭代器对象(该对象所属的类已经实现__next__方法),实现了该方法则该对象可在for循环中迭代不断返回下一个值

    class Fibs:
        def __init__(self):
            self.a = 0
            self.b = 1
        def __next__(self):
            self.a, self.b = self.b, self.a + self.b
            return self.a
        def __iter__(self):
            return self
            
    >>>fibs = Fibs()
    >>>next(fibs)
    1
    >>>next(fibs)
    2
    >>>for f in fibs:
    ...    if f > 1000:
    ...        print(f)
    ...        break
            
    1597
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    cle/details/111863037)

    __next__返回迭代器对象的下一个值(如果没有抛出StopIteration异常),实现了该方法则该对象可以作为next(__x)的参数不断返回下一个值
    __iter__返回一个迭代器对象(该对象所属的类已经实现__next__方法),实现了该方法则该对象可在for循环中迭代不断返回下一个值

    class Fibs:
        def __init__(self):
            self.a = 0
            self.b = 1
        def __next__(self):
            self.a, self.b = self.b, self.a + self.b
            return self.a
        def __iter__(self):
            return self
            
    >>>fibs = Fibs()
    >>>next(fibs)
    1
    >>>next(fibs)
    2
    >>>for f in fibs:
    ...    if f > 1000:
    ...        print(f)
    ...        break
            
    1597
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    在使用yum -y install python-openstackclient下载openstack云计算平台管理客户端时
    【算法|双指针系列No.6】leetcode LCR 179. 查找总价格为目标值的两个商品
    【JavaScript】设计模式
    SQL必需掌握的100个重要知识点:IN 操作符
    Cypress的安装与启动
    leakCanary原理
    HappyGBS GB28181信令服务 - 开篇
    Sentinel: 分布式系统的流量防卫兵
    【图像处理 】001 Android 中 Bitmap 压缩的几种方法浅析
    华为od德科面试数据算法解析 2022-6-27 字符串片段反转
  • 原文地址:https://blog.csdn.net/qq_42283621/article/details/126168539