一文读懂什么是Python魔法函数
一文读懂什么是Python魔法函数
Python的魔法函数是指Python的类中,一系列函数名由双下划线包裹的函数。
笔者最初接触到魔法函数的使用是在Pytorch中,在Pytorch中的Dataset类中有这样的用法:
除了常见的__init__构造函数外,还有__getitem__和__len__函数。在之后的代码中,笔者并没有看到__getitem__和__len__函数的显示调用。那么这样的声明与定义有什么意义?
首先定义一个空类,并用dir
方法获取类中的所有方法(一个空类真的是空空如也吗?)
class Foo:passprint(dir(Foo))
结果:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
我们可以看到许多默认的方法。比如每一个类都有一个默认的__init__方法作为其构造函数。而如果想定义自己的构造函数,就需要显式地对构造函数进行定义。
下面结合实例来说明一些魔法函数的用处。
基本
__new__(cls[,args…])
一个对象实例化的时候所调用的第一个方法。
__init__(self[, args…])
默认的构造函数,用于类的初始化。
注:__init__和__new__的区别:
在一般情况下,我们在构造类时调用的是__init__,但实际上第一个被调用的方法是__new__。以下代码为证:
class Bar:def __new__(cls, num):print("use __new__ method")return super(Bar, cls).__new__(cls)def __init__(self, num):print("use __init__ method")self.num = num bar = Bar(1)
结果为:
use __new__ method use __init__ method
一般情况下,我们放心使用__init__方法进行对象的构造即可,只需大致理解__new__和__init__的区别即可:
__new__
:创建对象时调用,会返回当前对象的一个实例
__init__
:创建完对象后调用,对当前对象的一些实例初始化,无返回值
__str__(self)
定义使用print()时的行为。
__repr__(self)
与str方法类似,但更面向开发者。如果一个类同时定义str()和repr(),那么会优先使用str()。
注:str和repr的返回值必须为str
__call__(self[, args…])
像函数一样调用类的实例。可以接参数。
__get__(self)
定义用对象为其他成员赋值的行为。
__set__(self[,args…])
定义为其他数据类型为对象赋值时的行为。
__del__(self)
默认的析构函数。
代码实例:
class Foo:def __init__(self,num):self.num = numprint("constructor")def __del__(self):print("destructor")def __repr__(self):return "the repr"def __call__(self, a):print("__call__ is used, the value is {}".format(a))def __get__(self):return self.numdef __set__(self,num):self.num = numfoo = Foo(0) # __init__
print(foo) # __str__或__repr__
foo(1) # __call__
foo = 2 # __set__
num = foo # __get__
# 析构
print(num)
运算符重载
Python的类中定义了大量一元运算符、二元运算符、类型转换运算符等。此处不再一一赘述。
lt(self, other) | 定义小于号的行为:x < y 调用 x.lt(y) |
---|---|
le(self, other) | 定义小于等于号的行为:x <= y 调用 x.le(y) |
eq(self, other) | 定义等于号的行为:x == y 调用 x.eq(y) |
ne(self, other) | 定义不等号的行为:x != y 调用 x.ne(y) |
gt(self, other) | 定义大于号的行为:x > y 调用 x.gt(y) |
ge(self, other) | 定义大于等于号的行为:x >= y 调用 x.ge(y) |
add(self, other) | 定义加法的行为:+ |
sub(self, other) | 定义减法的行为:- |
mul(self, other) | 定义乘法的行为:* |
truediv(self, other) | 定义真除法的行为:/ |
floordiv(self, other) | 定义整数除法的行为:// |
mod(self, other) | 定义取模算法的行为:% |
divmod(self, other) | 定义当被 divmod() 调用时的行为 |
pow(self, other[, modulo]) | 定义当被 power() 调用或 ** 运算时的行为 |
lshift(self, other) | 定义按位左移位的行为:<< |
rshift(self, other) | 定义按位右移位的行为:>> |
and(self, other) | 定义按位与操作的行为:& |
xor(self, other) | 定义按位异或操作的行为:^ |
or(self, other) | 定义按位或操作的行为:| |
radd(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
rsub(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
rmul(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
rtruediv(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
rfloordiv(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
rmod(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
rdivmod(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
rpow(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
rlshift(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
rrshift(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
rand(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
rxor(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
ror(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
iadd(self, other) | 定义赋值加法的行为:+= |
isub(self, other) | 定义赋值减法的行为:-= |
imul(self, other) | 定义赋值乘法的行为:*= |
itruediv(self, other) | 定义赋值真除法的行为:/= |
ifloordiv(self, other) | 定义赋值整数除法的行为://= |
imod(self, other) | 定义赋值取模算法的行为:%= |
ipow(self, other[, modulo]) | 定义赋值幂运算的行为:**= |
ilshift(self, other) | 定义赋值按位左移位的行为:<<= |
irshift(self, other) | 定义赋值按位右移位的行为:>>= |
iand(self, other) | 定义赋值按位与操作的行为:&= |
ixor(self, other) | 定义赋值按位异或操作的行为:^= |
ior(self, other) | 定义赋值按位或操作的行为:|= |
pos(self) | 定义正号的行为:+x |
neg(self) | 定义负号的行为:-x |
abs(self) | 定义当被 abs() 调用时的行为 |
invert(self) | 定义按位求反的行为:~x |
complex(self) | 定义当被 complex() 调用时的行为(需要返回恰当的值) |
int(self) | 定义当被 int() 调用时的行为(需要返回恰当的值) |
float(self) | 定义当被 float() 调用时的行为(需要返回恰当的值) |
round(self[, n]) | 定义当被 round() 调用时的行为(需要返回恰当的值) |
容器
假设对象名为foo:
__len__(self)
定义调用len()时的返回值。(必须为int)
__getitem__(self,index)
定义调用foo[index]的返回值。
__setitem__(self,index,value)
定义为foo[index]赋值为value的行为。
__delitem__(self, key)
删除指定索引对应的元素。
__contains__(self, item)
判断序列是否包含指定元素。
迭代
__iter__(self)
生成迭代对象时调用,返回值必须是对象自己。
__next__(self)
每一次for循环都调用该方法。
如果一个类实现了iter()和next()方法,那么就认为它是一个可迭代对象。
以下用一个简单的实例(简单的dataloader)说明上述函数的用法:
class Dataloader:def __init__(self,picList):self.picList = picListself.index = -1def __len__(self):return len(self.picList)def __getitem__(self,index):return self.picList[index]def __setitem__(self,index,value):self.picList[index] = valuedef __delitem__(self,index):print("{} will be deleted".format(self.picList[index]))del(self.picList[index])def __contains__(self,name):return self.picList.__contains__(name)def __iter__(self):return selfdef __next__(self):self.index+=1if(self.index<len(self)):return self.picList[self.index]else:raise StopIterationif __name__ == '__main__':picList = ['cat.png','dog.png','sheep.png','pig.png']dataloader = Dataloader(picList)# __len__print(len(dataloader))# __getitem__pic1 = dataloader[2]print(pic1)# __setitem__dataloader[2] = 'horse.png'# __contains__print('horse.png' in dataloader)# __delitem__del(dataloader[2])print(len(dataloader))# __iter__和__next__for pic in dataloader:print(pic)
回头再看开头的那个pytorch程序,是不是就没那么难了呢?
后记
实际上Python的魔法函数远不止这些。感兴趣的读者可以参阅https://rszalski.github.io/magicmethods/
一文读懂什么是Python魔法函数相关推荐
- 一文读懂:从 Python 打包到 CLI 工具
最近项目组在写项目的 CLI 工具,已经接近尾声,想做成 pip 的安装包,所以才有了这篇文章. 1,文章介绍了如何生成 Python Egg ,上传 PyPI 及其 pip 的安装测试 2,在后面的 ...
- 一文读懂 JavaScript 和 Python 九大语义区别
作者 | Ruqayyah Sara 译者 | 弯月,责编 | 伍杏玲 出品 | CSDN(ID:CSDNnews) 我是一名全栈开发.前几天我一直在研究算法和数据结构,因为对于程序员而言,最重要能力 ...
- 一文读懂如何用python调用matlab函数(windows环境)
第一步配置环境: 要安装引擎 API,请在操作系统提示符下执行以下命令,其中 matlabroot 是 MATLAB 文件夹的路径.您可能需要管理员权限才能执行这些命令.或者,使用在非默认位置安装用于 ...
- python读取枚举_一文读懂Python 枚举
enum是一组绑定到唯一常数值的符号名称,并且具备可迭代性和可比较性的特性.我们可以使用 enum 创建具有良好定义的标识符,而不是直接使用魔法字符串或整数,也便于开发工程师的代码维护. 创建枚举 我 ...
- python输入什么就输出什么_一文读懂Python的输入和输出
本文介绍了Python的输入和输出,既然是Python代码,那么就一定有输出量,那么,Python是如何输出的呢? 输出 用print()在括号中加上字符串,就可以向屏幕上输出指定的文字.比如输出'h ...
- python随机森林变量重要性_推荐 :一文读懂随机森林的解释和实现(附python代码)...
原标题:推荐 :一文读懂随机森林的解释和实现(附python代码) 作者:WilliamKoehrsen:翻译:和中华:校对:李润嘉 本文约6000字,建议阅读15分钟. 本文从单棵决策树讲起,然后逐 ...
- 一文读懂NLP之隐马尔科夫模型(HMM)详解加python实现
一文读懂NLP之隐马尔科夫模型(HMM)详解加python实现 1 隐马尔科夫模型 1.1 HMM解决的问题 1.2 HMM模型的定义 1.2.1HMM的两个假设 1.2.2 HMM模型 1.3 HM ...
- 实时社群技术专题(一):支持百万人超级群聊,一文读懂社群产品Discord
本文由腾讯产品体验设计师volihuang分享,原题"千万级增长,实时社交产品Discord拆解",本文收录时有内容修订和大量排版优化. 1.引言 对于大多数人而言,对即时通讯IM ...
- 一文读懂Faster RCNN
来源:信息网络工程研究中心本文约7500字,建议阅读10+分钟 本文从四个切入点为你介绍Faster R-CNN网络. 经过R-CNN和Fast RCNN的积淀,Ross B. Girshick在20 ...
最新文章
- C# SortedDictionary以及SortedList的浅谈
- 二、Windows下TortoiseGit的安装与配置
- MySQL—事务隔离级别
- 【操作】Json取value时,为什么得到的是undefined?
- HttpClient的几个实现类
- Hive的基本操作-自定义函数
- python写接口测试代码_python写运单接口测试(增改查)完整代码
- 如何用python画组合图形_python结合G2绘制精美图形
- BZOJ5292 洛谷4457 LOJ2513:[BJOI2018]治疗之雨——题解
- qq邮箱html模板_用了这么多简历模板,发现只有QQ邮箱自带的模板最好用
- maven2 clean 错误的解决
- Scala深入浅出实战经典---001-Scala开发环境搭建和HelloWorld解析
- 数字逻辑电路期末复习与常见问题
- word2vec模型保存为npy文件 clh
- 服务器接显示器重影,学生能够选择影音服务器中的考试试卷进行自测测试结束系统将自动批阅并显示标.doc...
- 漏洞修复:Insecure Transport: HSTS not Set
- 11.2.1 绝对值函数
- 河海大学计算机专业戴慧凤,特色宿舍 - 河海大学学生工作处.doc
- Soul 网关(一)---- 架构设计简介、soul-admin、soul-bootstrap
- 80、消防应急照明和疏散指示的要求
热门文章
- 1762 牛的洗牌(递推)
- SASS的概念和使用
- 你很牛,且是刚毕业的,那就到华为上班吧!--绝对隐私:华为员工待遇全面揭秘...
- 服务器更新宕机-自我检讨
- 两个质数互质是_两个质数一定是互质数_互质数和质数的区别_分解质因数的方法_互为质数和互质数...
- 软件测试面试题之如何对web系统进行全面测试(持续更新中,求关注)
- 闲鱼上怎么引流学生粉?闲鱼如何引流客源?闲鱼的引流技巧
- 龙王传说古月_龙王传说:古月罕见表现脆弱一面,惹人怜爱。老巫婆蔡老终于出场...
- 前置++和后置++区别
- 职业生涯规划jd网上商城