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__

2)对象类名 或 函数名

class TestC:
    pass


def testM():
    pass


print(type(TestC()))
print(TestC().__class__)
# <class '__main__.TestC'>
# <class '__main__.TestC'>

print(type(TestC()).__name__)
print(TestC().__class__.__name__)
# TestC
# TestC

print(testM.__name__)
# testM

__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

__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

__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

__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

__fspath__(self)

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

import os


class Test:
    def __fspath__(self):
        return 'home/malloclu/TestObject'


print(os.fspath(Test()))
# home/malloclu/TestObject

(浅)复制与深复制

已存在类型

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]}

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]}]}

自定义类型

(浅)复制和深复制要分别实现__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]

运算符重载

二元运算符

方法列表

符号运算反运算增量赋值运算(例如+=-=等)备注
+__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'
# 不推荐
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'

增量赋值运算

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)

一元运算符

方法列表

符号方法备注
-__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

迭代器

详细查看该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

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MallocLu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值