详解Python常用的魔法方法


Posted in Python onJune 03, 2021

一、python魔法方法

Python的魔法方法会在特定的情况下自动调用,且他们的方法名通常被双下划线包裹,之前我们学习的构造函数和析构函数就属于魔法方法

二、运算符重载

Python中同样有运算符重载,其实所有的运算符都是使用了对应的魔法方法来处理的对象的,魔法方法对应的操作符如下

详解Python常用的魔法方法

我们来举一个简单的例子

class A:
    def __init__(self,x):
        self.x = x
    def __add__(self,other):
        return int(self.x)+int(other.x)
a = A(3.3)
b = A(5.2)
print(a+b)

类似的还有反运算重载和增量复制运算,用处较少,不再解释

详解Python常用的魔法方法
详解Python常用的魔法方法

三、打印操作的魔法方法

__str__(self):返回值是str类型的,当我们需要以字符串的形式输出对象时(调用print时),就会自动调用该方法,举个例子

class A:
    def __str__(self):
        return '我真帅'

a = A()
print(a)# 我真帅

__repr__(self):返回值是str类型的,当我们直接在shell中输入对象名并按下回车,就会自动调用该方法,他也有和__str__一样的功能,但如果两者你都重写了,在使用print时,__str__的优先级高,__repr__是给机器看的,__str__是给人看的,举个例子

>>> class A:
    def __str__(self):
        return '我真帅'
    def __repr__(self):
        return '我是世界第一帅'

>>> a = A()
>>> a
我是世界第一帅
>>> print(a)
我真帅

四、属性操作的魔法方法

  • __getattr__(self, name):定义当用户试图获取一个不存在的属性时的行为,其中name是属性名,是一个字符串,下同
  • __getattribute__(self, name):定义当该类的属性被访问时的行为,该方法默认返回该属性的值
  • __setattr__(self, name, value):定义当一个属性被设置时的行为,value是给该属性的值
  • __delattr__(self, name):定义当一个属性被删除时的行为

例如:

class A:
    def __init__(self):
        self.id = "Pyhon"
    def __getattr__(self,name):
        print(name+"这个属性不存在")
    def __getattribute__(self,name):
        print("我访问了"+name+"这个属性")
        return super().__getattribute__(name)
    def __setattr__(self,name,value):
        print("将属性"+name+"置为"+value)
        super().__setattr__(name,value)
    def __delattr__(self,name):
        print("将属性"+name+"删除了");
        super().__delattr__(name)
    def fun(self):
        pass
a = A()
a.name
a.name = "老师"
del a.name
a.fun()
# output:
# 将属性id置为Pyhon
# 我访问了name这个属性
# name这个属性不存在
# 将属性name置为老师
# 将属性name删除了
# 我访问了fun这个属性

结果可以看出,当我们访问一个属性的时候,先是调用了__getattribute__,如果该属性不存在,则再调用__getattr__

使用这几个的方法的时候,要注意不要陷入无限递归,运算符重载的时候也容易犯这种错误,例如下面的错误

class A:
    def __init__(self):
        self.id = "Pyhon"
    def __setattr__(self,name,value):
        print("将属性"+name+"置为"+value)
        if(name == "id"):
            self.id = value

a = A()

执行这段程序的时候将陷入无限递归,原因是在__setattr__中,直接给self对象的属性赋值,而这又会调用__setattr__方法。

所以在__setattr__中,我们通常会使用父类的__setattr__方法来给self对象的属性赋值,这不会陷入无限递归,其他几个方法和运算符重载也是同理,上面程序订正后如下

class A:
    def __init__(self):
        self.id = "Pyhon"
    def __setattr__(self,name,value):
        print("将属性"+name+"置为"+value)
        if(name == "id"):
            super().__setattr__(name,value)

a = A()
# output
# 将属性id置为Pyhon

五、描述符

  • __get__(self, instance, owner):通过其他实例对象来访问该类的实例对象时会调用该方法,返回该实例对象的引用。其中instance是访问该对象的实例对象的引用,下同,owner是访问该对象的类对象
  • __set__(self, instance, value):通过其他实例对象来给该类的实例对象赋值时会调用该方法。其中value是给该对象赋的值
  • __delete__(self, instance):通过其他实例对象来删除该类的实例对象时会调用该方法
class Fit:
    def __init__(self):
        self.height = 180
        self.weight = 80
    def __get__(self,instance,owner):
        print("get:",instance,owner)
        return [self.height,self.weight]
    def __set__(self,instance,value):
        print("set:",instance,value)
        self.height = value
        self.weight = value/2
    def __delete__(self,instance):
        del self.height
        del self.weight
        print("delete:",instance)

class Test:
    fit = Fit()
        
t = Test()
print (t.fit)
t.fit = 190
del t.fit
# output:
# get: <__main__.Test object at 0x0000023EFFA738C8> <class '__main__.Test'>
# [180, 80]
# set: <__main__.Test object at 0x0000023EFFA738C8> 190
# delete: <__main__.Test object at 0x0000023EFFA738C8>

通常情况下,上面几个魔法方法,当我们需要定义一个属性,且希望可以直接对该属性进行相应的操作,而不是通过调用方法的方式来进行操作时,我们可以定义一个该属性的类,实现上面几个魔法方法,将需要用到的属性作为其实例对象,这样就完成了,例如上面的Fit,其实就是体型类,而Test中有一个体型属性叫fit,我们在Fit中定义了一些对Fit的实例对象操作时执行的操作。

六、定制序列

  • __len__(self):定义当该类的实例对象被len()调用时的行为
  • __getitem__(self, key):定义获取该类的实例对象中指定元素的行为,也就是说执行self[key]时的行为
  • __setitem__(self, key, value):定义设置该类的实例对象中指定元素的行为,相当于self[key] = value
  • __delitem__(self, key):定义删除该类的实例对象中指定元素的新闻,相当于del self[key]
class CountList:
    def __init__(self,*args):
        self.values = [x for x in args]#这是一个列表推导式,把args里的元素作为values的元素
        self.count = {}.fromkeys(range(len(self.values)),0)

    def __len__(self):
        return len(self.values)

    def __getitem__(self,key):
        self.count[key] += 1;
        return self.values[key]

c = CountList(1,3,5,7,9,11)
print(c[1])
print(c[1]+c[2])
print(c.count)
# output:
# 3
# 8
# {0: 0, 1: 2, 2: 1, 3: 0, 4: 0, 5: 0}

该类中的count是记录对应元素被访问的次数,其他两个也差不多,不再举例了

七、迭代器

迭代器,就是提供了迭代方法的容器,而所谓的迭代方法,就是下面这两个__iter____next__
可迭代,就是提供了__iter__方法的容器,我们之前讲的字符串,列表,元组,字典,集合都是可迭代的,但他们不是迭代器,可以使用Python的内置函数iter(iterable)来获取他们相应的迭代器,而迭代器使用next(iterator)可以获取下一个元素,而这两个方法其实就是调用了迭代器的__iter____next__

  • __iter__(self):定义获取迭代器时的行为
  • __next__(self):定义获取迭代器对应的下一个元素时的行为
class Fb:
    def __init__(self,n = 20):
        self.a = 0
        self.b = 1
        self.n = n
    def __iter__(self):
        return self
    def __next__(self):
        t = self.a
        self.a = self.b
        self.b = t + self.b
        if(self.a <= self.n):
            return self.a
        else:
            raise StopIteration

f = Fb()
for i in f:
    print(i,end=' ')
# output:1 1 2 3 5 8 13

其中 raise 是返回一个异常,上面的程序等价于下面这个

class Fb:
    def __init__(self,n = 20):
        self.a = 0
        self.b = 1
        self.n = n
    def __iter__(self):
        return self
    def __next__(self):
        t = self.a
        self.a = self.b
        self.b = t + self.b
        if(self.a <= self.n):
            return self.a
        else:
            raise StopIteration

f = Fb()
it = iter(f)
while True:
    try:
        i = next(it)
        print(i, end=' ')
    except StopIteration:
        break;

这样我们就很清楚Python中for循环的原理了,先通过iter来获取迭代器对象,然后不断调用next来获取下一个元素赋值给i,直到遇到StopIteration异常

到此这篇关于详解Python常用的魔法方法的文章就介绍到这了,更多相关python魔法方法内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
详解Python中的序列化与反序列化的使用
Jun 30 Python
在win和Linux系统中python命令行运行的不同
Jul 03 Python
Python SqlAlchemy动态添加数据表字段实例解析
Feb 07 Python
python实现点对点聊天程序
Jul 28 Python
Python实现堡垒机模式下远程命令执行操作示例
May 09 Python
python 实现在一张图中绘制一个小的子图方法
Jul 07 Python
python常用库之NumPy和sklearn入门
Jul 11 Python
Python企业编码生成系统之主程序模块设计详解
Jul 26 Python
python输出数组中指定元素的所有索引示例
Dec 06 Python
使用Jupyter notebooks上传文件夹或大量数据到服务器
Apr 14 Python
Jupyter notebook命令和编辑模式常用快捷键汇总
Nov 17 Python
python实现简单的三子棋游戏
Apr 28 Python
Python自动化之批量处理工作簿和工作表
Jun 03 #Python
Jupyter Notebook内使用argparse报错的解决方案
Python实现机器学习算法的分类
Jupyter Notebook 如何修改字体和大小以及更改字体样式
Python数据可视化之用Matplotlib绘制常用图形
使用numpy实现矩阵的翻转(flip)与旋转
Jun 03 #Python
详解Python生成器和基于生成器的协程
You might like
php开发工具之vs2005图解
2008/01/12 PHP
解析linux下安装memcacheq(mcq)全过程笔记
2013/06/27 PHP
PHP使用range协议实现输出文件断点续传代码实例
2014/07/04 PHP
php、mysql查询当天,查询本周,查询本月的数据实例(字段是时间戳)
2017/02/04 PHP
实现PHP中session存储及删除变量
2018/10/15 PHP
PHP实现基本留言板功能原理与步骤详解
2020/03/26 PHP
Jquery 基础学习笔记之文档处理
2009/05/29 Javascript
让jQuery与其他JavaScript库并存避免冲突的方法
2013/12/23 Javascript
利用JQuery和Servlet实现跨域提交请求示例分享
2014/02/12 Javascript
jquery实现简单的全选和反选功能
2016/01/02 Javascript
JS常见疑难点分析之match,charAt,charCodeAt,map,search用法分析
2016/12/25 Javascript
vue使用stompjs实现mqtt消息推送通知
2017/06/22 Javascript
JavaScript设计模式之装饰者模式实例详解
2019/01/17 Javascript
JQuery判断radio单选框是否选中并获取值的方法
2019/01/17 jQuery
vue自定义指令directive的使用方法
2019/04/07 Javascript
10个最受欢迎的 JavaScript框架(推荐)
2019/04/24 Javascript
LayUI动态设置checkbox不显示的解决方法
2019/09/02 Javascript
openlayers 3实现车辆轨迹回放
2020/09/24 Javascript
python调用机器喇叭发出蜂鸣声(Beep)的方法
2015/03/23 Python
仅利用30行Python代码来展示X算法
2015/04/01 Python
python日志记录模块实例及改进
2017/02/12 Python
Python多进程multiprocessing、进程池用法实例分析
2020/03/24 Python
Windows+Anaconda3+PyTorch+PyCharm的安装教程图文详解
2020/04/03 Python
详解python datetime模块
2020/08/17 Python
python中watchdog文件监控与检测上传功能
2020/10/30 Python
日本运动品牌美津浓官方购物网站:MIZUNO SHOP
2016/08/21 全球购物
男女钓鱼靴和甲板鞋:XTRATUF
2021/01/09 全球购物
初中体育教学反思
2014/01/14 职场文书
信访工作者先进事迹
2014/01/17 职场文书
幼儿园教师国培感言
2014/02/02 职场文书
质量负责人任命书
2014/06/06 职场文书
学习走群众路线心得体会
2014/11/05 职场文书
转让协议书
2015/01/27 职场文书
入团介绍人意见范文
2015/06/04 职场文书
mysql中int(3)和int(10)的数值范围是否相同
2021/10/16 MySQL
Nginx性能优化之Gzip压缩设置详解(最大程度提高页面打开速度)
2022/02/12 Servers