详解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设置检查点简单实现代码
Jul 01 Python
详解Python中的循环语句的用法
Apr 09 Python
Python读取Excel的方法实例分析
Jul 11 Python
Python闭包的两个注意事项(推荐)
Mar 20 Python
python九九乘法表的实例
Sep 26 Python
浅谈使用Python变量时要避免的3个错误
Oct 30 Python
python编程培训 python培训靠谱吗
Jan 17 Python
python语言基本语句用法总结
Jun 11 Python
Python 中的 import 机制之实现远程导入模块
Oct 29 Python
Python读取分割压缩TXT文本文件实例
Feb 14 Python
python使用dlib进行人脸检测和关键点的示例
Dec 05 Python
pandas数值排序的实现实例
Jul 25 Python
Python自动化之批量处理工作簿和工作表
Jun 03 #Python
Jupyter Notebook内使用argparse报错的解决方案
Python实现机器学习算法的分类
Jupyter Notebook 如何修改字体和大小以及更改字体样式
Python数据可视化之用Matplotlib绘制常用图形
使用numpy实现矩阵的翻转(flip)与旋转
Jun 03 #Python
详解Python生成器和基于生成器的协程
You might like
让你的网站首页自动选择语言转跳
2006/12/06 PHP
php中curl使用指南
2015/02/05 PHP
图文详解PHP环境搭建教程
2016/07/16 PHP
PHP静态成员变量
2017/02/14 PHP
PHP 对象接口简单实现方法示例
2020/04/13 PHP
用js实现键盘方向键翻页功能的代码
2007/06/03 Javascript
js操作select控件的几种方法
2010/06/02 Javascript
js将字符串转成正则表达式的实现方法
2013/11/13 Javascript
最简单的tab切换实例代码
2016/05/13 Javascript
bootstrap daterangepicker汉化以及扩展功能
2017/06/15 Javascript
基于Vue实例对象的数据选项
2017/08/09 Javascript
javaScript中&quot;==&quot;和&quot;===&quot;的区别详解
2018/03/16 Javascript
Angular6 写一个简单的Select组件示例
2018/08/20 Javascript
全面解析vue router 基本使用(动态路由,嵌套路由)
2018/09/02 Javascript
微信小程序导入Vant报错VM292:1 thirdScriptError的解决方法
2019/08/01 Javascript
JavaScript检测是否开启了控制台(F12调试工具)
2020/10/02 Javascript
Python解析excel文件存入sqlite数据库的方法
2016/11/15 Python
python 数据清洗之数据合并、转换、过滤、排序
2017/02/12 Python
python中import reload __import__的区别详解
2017/10/16 Python
浅谈python中的占位符
2017/11/09 Python
新手如何发布Python项目开源包过程详解
2019/07/11 Python
使用python模拟命令行终端的示例
2019/08/13 Python
使用Pycharm分段执行代码
2020/04/15 Python
基于HTML5 Canvas 实现商场监控实例详解
2017/11/20 HTML / CSS
德国鞋子网上商店:Omoda.de
2017/03/31 全球购物
NBA欧洲商店(英国):NBA Europe Store UK
2018/07/27 全球购物
STP的判定过程
2012/10/01 面试题
《山谷中的谜底》教学反思
2014/04/26 职场文书
结婚保证书范文
2014/04/29 职场文书
新闻传播专业求职信
2014/07/22 职场文书
擅自离岗检讨书
2014/09/12 职场文书
工厂见习报告范文
2014/10/31 职场文书
营销计划书范文
2015/01/17 职场文书
2015年高校辅导员工作总结
2015/04/20 职场文书
小学数学教师研修感悟
2015/11/18 职场文书
nginx从安装到配置详细说明(安装,安全配置,防盗链,动静分离,配置 HTTPS,性能优化)
2022/02/12 Servers