你好,我是kelly。
在Python中,以"__"双下划线开头和结尾的方法,称为Magic Method(魔术方法)。
根据用途,将魔法方法划分为不同种类:
一、运算符重载
Python对象之间运算,比如四则运算,实际是使用了魔法方法,如下图所示,在ipython的命令行窗口下,按Tab强制提示时,会出现整数变量a的魔法方法__add__。
定义类的四则运算(__add__、__sub__、__mul__):
class Value(object):
def __init__(self, x):
self.x = x
def __add__(self, other):
return self.x + other.x
def __sub__(self, other):
return self.x - other.x
def __mul__(self, other):
return self.x * other.x
a = Value(10)
b = Value(20)
print(a + b)
print(a - b)
print(a * b)
结果:
30
-10
200
二、元类
定义类之后,当对类进行实例化时,
step1:先调用__new__创建一个实例
step2:再调用__init_对实例赋值初始化赋值
class Test(object):
def __new__(cls, *args, **kwargs):
print("调用__new__")
return super(Test, cls).__new__(cls)
def __init__(self, x, y):
self.x = x
self.y = y
print("调用__init__")
Test(10, 100)
结果:
调用__new__
调用__init__
三、对象的字符串描述
__str__和__iter__均是输出对象的字符串表示:__str__在使用str()函数或者print()函数时,自动调用;而__iter__在使用iter()函数或者在命令行窗口输入对象名时,自动调用。
各自的触发场景
此外,
__str__:面向用户,显示的信息更人性化。
__repr__:面向开发、终端,显示的信息更全。
In [70]: now = datetime.datetime.now()
In [71]: import datetime
In [72]: now = datetime.datetime.now()
In [73]: str(now)
Out[73]: '2024-01-02 19:26:18.562440'
In [74]: repr(now)
Out[74]: 'datetime.datetime(2024, 1, 2, 19, 26, 18, 562440)'
四、让类实例像函数一样被调用
__call__函数可以让类实例可以像函数一样被调用。
class Test(object):
def __call__(self, *args, **kwargs):
print("__call__被调用了!")
obj = Test()
obj()
结果:
__call__被调用了!
五、对象属性
__len__函数让类实例可以使用len函数:
class Test(object):
def __init__(self, x):
self.x = x
def __call__(self, *args, **kwargs):
return "__call__被调用了!"
def __len__(self):
return len(self.x)
obj = Test([1, 2, 3, 4, 5])
print(obj())
print(len(obj))
结果:
__call__被调用了!
5
六、索引访问
当访问对象的属性不存在时,调用__getattr__。
__setattr__:顾名思义,对类实例执行设置操作时调用(属性赋值)。
__setitem__、__getitem__:使用索引方式对类实例进行赋值和获取操作时调用。
class Test(object):
def __init__(self, x, y=None):
print("begin __init__")
self.x = x
self.y = y
print("end __init__")
def __call__(self, *args, **kwargs):
return "__call__被调用了!"
def __len__(self):
return len(self.x)
def __getattr__(self, item):
print("__getattr__被调用了!")
def __setattr__(self, key, value):
print("__setattr__被调用了!")
super(Test, self).__setattr__(key, value)
def __getitem__(self, item):
print("__getitem__被调用了!")
return self.x[item]
def __setitem__(self, key, value):
print("__setitem__被调用了!")
self.x[key] = value
结果:
属性u不存在,__getattr__被调用。
1、类Test的__init__函数中存在2个属性赋值,__setattr__被调用2次。
2、属性z本来不存在,__setattr__被调用1次。
3、通过索引方式,对类实例进行索引取值操作,调用__getitem__函数。
4、通过索引方式,对类实例索引赋值操作,调用__setitem__函数。
本文原始版本发表链接:
kelly会在公众号「kelly学技术」不定期更新文章,感兴趣的朋友可以关注一下,期待与您交流。
--over--