详解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通过exifread模块获得图片exif信息的方法
Mar 16 Python
python魔法方法-属性访问控制详解
Jul 25 Python
python opencv之SIFT算法示例
Feb 24 Python
Python使用selenium实现网页用户名 密码 验证码自动登录功能
May 16 Python
python 实现矩阵上下/左右翻转,转置的示例
Jan 23 Python
pandas去除重复列的实现方法
Jan 29 Python
Python二维码生成识别实例详解
Jul 16 Python
python数据化运营的重要意义
Nov 25 Python
Python爬取爱奇艺电影信息代码实例
Nov 26 Python
python通过移动端访问查看电脑界面
Jan 06 Python
Python机器学习之基础概述
May 19 Python
Python 统计序列中元素的出现频度
Apr 26 Python
Python自动化之批量处理工作簿和工作表
Jun 03 #Python
Jupyter Notebook内使用argparse报错的解决方案
Python实现机器学习算法的分类
Jupyter Notebook 如何修改字体和大小以及更改字体样式
Python数据可视化之用Matplotlib绘制常用图形
使用numpy实现矩阵的翻转(flip)与旋转
Jun 03 #Python
详解Python生成器和基于生成器的协程
You might like
一个可查询所有表的“通用”查询分页类
2006/10/09 PHP
php中通过正则表达式下载内容中的远程图片的函数代码
2012/01/10 PHP
PHP脚本监控Nginx 502错误并自动重启php-fpm
2015/05/13 PHP
PHP框架laravel的.env文件配置教程
2017/06/07 PHP
PHP设计模式之观察者模式定义与用法示例
2018/08/04 PHP
javascript 对表格的行和列都能加亮显示
2008/12/26 Javascript
JSON扫盲帖 JSON.as类教程
2009/02/16 Javascript
通过jQuery打造支持汉字,拼音,英文快速定位查询的超级select插件
2010/06/18 Javascript
一个可绑定数据源的jQuery数据表格插件
2010/07/17 Javascript
基于JQuery的日期联动实现代码
2011/02/24 Javascript
js动态创建表格,删除行列的小例子
2013/07/20 Javascript
详解JavaScript函数绑定
2013/08/18 Javascript
JavaScript计时器示例分析
2015/02/05 Javascript
Jquery基础教程之DOM操作
2015/08/19 Javascript
Reactjs实现通用分页组件的实例代码
2017/01/19 Javascript
jQuery快速实现商品数量加减的方法
2017/02/06 Javascript
angularJS模态框$modal实例代码
2017/05/27 Javascript
JavaScript的词法结构精华篇
2018/10/17 Javascript
Vue+element 解决浏览器自动填充记住的账号密码问题
2019/06/11 Javascript
layui关闭弹窗后刷新主页面和当前更改项的例子
2019/09/06 Javascript
微信小程序点击生成朋友圈分享图(遇到的坑)
2020/06/17 Javascript
JS数据类型分类及常用判断方法
2020/11/19 Javascript
[00:43]DOTA2小紫本全民票选福利PA至宝全方位展示
2014/11/25 DOTA
python实现数据分析与建模
2019/07/11 Python
python爬虫 基于requests模块发起ajax的get请求实现解析
2019/08/20 Python
Pytorch 图像变换函数集合小结
2021/02/01 Python
西班牙英格列斯百货英国官网:El Corte Inglés英国
2017/10/30 全球购物
UGG澳洲官网:UGG Australia
2018/04/26 全球购物
杭州-DOTNET笔试题集
2013/09/25 面试题
承诺书的格式范文
2014/03/28 职场文书
学生保证书范文
2014/04/28 职场文书
向国旗敬礼活动总结范文2014
2014/09/27 职场文书
党的群众路线教育实践活动总结材料
2014/10/30 职场文书
自主招生推荐信怎么写
2015/03/26 职场文书
使用canvas对video视频某一刻截图功能
2021/09/25 HTML / CSS
Javascript设计模式之原型模式详细
2021/10/05 Javascript