详解Python常用的魔法方法
作者:啦哆咪 发布时间:2022-01-22 05:44:03
一、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)
类似的还有反运算重载和增量复制运算,用处较少,不再解释
三、打印操作的魔法方法
__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异常
来源:https://blog.csdn.net/qq_43713303/article/details/117419455
猜你喜欢
- 双向链表一种更复杂的链表是“双向链表”或“双面链表”。每个节
- 一、背景介绍在 Python 项目开发过程中,根据不同的项目场景,需要切换不同的 Python 版本。因此,我们经常会对不同的项目,创建特定
- 今天分享一下Django实现的简单的文件上传的小例子。步骤 •创建Django项目,创建Django应用 •设计模型&n
- 利用Keras构建完普通BP神经网络后,还要会构建CNNKeras中构建CNN的重要函数1、Conv2DConv2D用于在CNN中构建卷积层
- 本文实例讲述了python类装饰器用法。分享给大家供大家参考。具体如下:#!coding=utf-8 registry = {} def r
- python中xmltodict使用xml转换成OrderedDict代码 :import xmltodictfrom pprin
- 在做数据库备份和还原数据库的时候出现"错误2812:未能找到存储过程’master.dbo.xp_fileexist’"
- 本文实例讲述了python获得文件创建时间和修改时间的方法。分享给大家供大家参考。具体如下:这里需要用户从控制台输入文件路径import o
- 类视图使用装饰器为类视图添加装饰器,可以使用两种方法。为了理解方便,我们先来定义一个为函数视图准备的装饰器(在设计装饰器时基本都以函数视图作
- 先给出一个四人团对Decorator mode的定义:动态地给一个对象添加一些额外的职责。再来说说这个模式的好处:认证,权限检查,记日志,检
- 如何生成指定区间中的随机数要求生成区间[a, b]中的随机数。若要求为浮点数,则Python中只能近似达到这一要求,因为随机函数的取值区间一
- 最近帮人做了个贪吃蛇的游戏(交作业用),很简单,界面如下:开始界面:游戏中界面:是不是很简单、朴素。(欢迎大家访问GitHub)游戏是基于P
- 以下为在asp中增加一个sql server2000用户函数,并为建立一个数据库,给他dbo的权限。注意:sql server的验证方式不要
- 简介XSStrike 是一款用于探测并利用XSS漏洞的脚本XSStrike目前所提供的产品特性:对参数进行模糊测试之后构建合适的payloa
- 在使用Python做socket编程时,由于需要使用阻塞(默认)的方式来读取数据流,此时对于数据的结束每次都需要自己处理,太麻烦。并且网上也
- 不少小伙伴认为,直接去操作excel,比我们利用各种代码数据去处理,直接又简单,不那么花里胡哨,但是在代码上,处理数据,直接的软件操作是行不
- 问题:之前在学习list和dict相关的知识时,遇到了一个常见的问题:如何在遍历list或dict的时候正常删除?例如我们在遍历dict的时
- js也是可以做出狂炫的图形的,恭请超级高手分析。给大家看个例子吧。http://www.p01.org/releases/DHTML_con
- 当变量维数加大时很难想象是怎样按不同维度求和的,高清楚一个,其他的应该就很清楚了,什么都不说了,上例子,例子一看便明白…..a=range(
- 前言:要说小时候称霸所有翻盖手机的小游戏,除了贪吃蛇,那就是推箱子了。控制小人将所有箱子放到指定位置,就是这样简简单单的操作,陪伴我度过了无