新用户注册入口 老用户登录入口

[转载]python 类的定制_Python基础:20类的定制

文章作者:转载 更新时间:2023-04-19 14:30:42 阅读数量:131
文章标签:Python__del__构造器析构器重载操作符
本文摘要:Python中,类的特殊方法(如`__init__`、`__del__`)为构造器和析构器提供了实现方式。这些双下划线前后包围的方法允许开发者自定义对象的行为,包括重载操作符、控制属性访问以及模拟标准类型等。例如,通过实现`__str__`和`__repr__`可以定制对象的显示输出。另外,在数值类型的类中,可通过覆盖如`__add__`、`__sub__`等方法以实现二进制运算符的重载,从而扩展类的功能并实现特定业务逻辑。在实际应用中,如Time60类通过实现特殊方法,不仅能够对小时和分钟进行相加操作,还能确保对象具有清晰的字符串表示形式,展示了Python特殊方法在实现类功能定制上的强大作用。
转载文章

本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_30849865/article/details/112989450。

该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。

作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。

如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。

中有一些可自定义的特殊方法,它们中的一些有预定义的默认行为,而其它一些则没有,留到需要的时候去实现。这些特殊方法是Python中用来扩充类的强有力的方式。它们可以实现模拟标准类型和重载操作符等。比如__init__()和__del__()就分别充当了构造器和析够器的功能。

这些特殊这些方法都是以双下划线(__)开始及结尾的。下表进行了总结:

基本定制型

C.__init__(self[, arg1, ...])

构造器(带一些可选的参数)

C.__new__(self[, arg1, ...])

构造器(带一些可选的参数);通常用在设置不变数据类型的子类。

C.__del__(self)

解构器

C.__str__(self)

可打印的字符输出;内建str()及print 语句

C.__repr__(self)

运行时的字符串输出;内建repr() 和``操作符

C.__unicode__(self)

Unicode 字符串输出;内建unicode()

C.__call__(self, *args)

表示可调用的实例

C.__nonzero__(self)

为object 定义False 值;内建bool() (从2.2 版开始)

C.__len__(self)

“长度”(可用于类);内建len()

对象(值)比较

C.__cmp__(self, obj)

对象比较;内建cmp()

C.__lt__(self, obj)

C.__le__(self, obj)

小于/小于或等于;对应

C.__gt__(self, obj)

C.__ge__(self, obj)

大于/大于或等于;对应>及>=操作符

C.__eq__(self, obj)

C.__ne__(self, obj)

等于/不等于;对应==,!=及<>操作符

属性

C.__getattr__(self, attr)

获取属性;内建getattr();仅当属性没有找到时调用

C.__setattr__(self, attr, val)

设置属性

C.__delattr__(self, attr)

删除属性

C.__getattribute__(self, attr)

获取属性;内建getattr();总是被调用

C.__get__(self, attr)

(描述符)获取属性

C.__set__(self, attr, val)

(描述符)设置属性

C.__delete__(self, attr)

(描述符)删除属性

数值类型:二进制操作符

C.__*add__(self, obj)

加;+操作符

C.__*sub__(self, obj)

减;-操作符

C.__*mul__(self, obj)

乘;*操作符

C.__*div__(self, obj)

除;/操作符

C.__*truediv__(self, obj)

True 除;/操作符

C.__*floordiv__(self, obj)

Floor 除;//操作符

C.__*mod__(self, obj)

取模/取余;%操作符

C.__*divmod__(self, obj)

除和取模;内建divmod()

C.__*pow__(self, obj[, mod])

乘幂;内建pow();**操作符

C.__*lshift__(self, obj)

左移位;<

数值类型:二进制操作符

C.__*rshift__(self, obj)

右移;>>操作符

C.__*and__(self, obj)

按位与;&操作符

C.__*or__(self, obj)

按位或;|操作符

C.__*xor__(self, obj)

按位与或;^操作符

数值类型:一元操作符

C.__neg__(self)

一元负

C.__pos__(self)

一元正

C.__abs__(self)

绝对值;内建abs()

C.__invert__(self)

按位求反;~操作符

数值类型:数值转换

C.__complex__(self, com)

转为complex(复数);内建complex()

C.__int__(self)

转为int;内建int()

C.__long__(self)

转 .long;内建long()

C.__float__(self)

转为float;内建float()

数值类型:基本表示法(String)

C.__oct__(self)

八进制表示;内建oct()

C.__hex__(self)

十六进制表示;内建hex()

数值类型:数值压缩

C.__coerce__(self, num)

压缩成同样的数值类型;内建coerce()

C.__index__(self)

在有必要时,压缩可选的数值类型为整型(比如:用于切片索引等等)

序列类型

C.__len__(self)

序列中项的数目

C.__getitem__(self, ind)

得到单个序列元素

C.__setitem__(self, ind,val)

设置单个序列元素

C.__delitem__(self, ind)

删除单个序列元素

C.__getslice__(self, ind1,ind2)

得到序列片断

C.__setslice__(self, i1, i2,val)

设置序列片断

C.__delslice__(self, ind1,ind2)

删除序列片断

C.__contains__(self, val)

测试序列成员;内建in 关键字

C.__*add__(self,obj)

串连;+操作符

C.__*mul__(self,obj)

重复;*操作符

C.__iter__(self)

创建迭代类;内建iter()

映射类型

C.__len__(self)

mapping 中的项的数目

C.__hash__(self)

散列(hash)函数值

C.__getitem__(self,key)

得到给定键(key)的值

C.__setitem__(self,key,val)

设置给定键(key)的值

C.__delitem__(self,key)

删除给定键(key)的值

C.__missing__(self,key)

给定键如果不存在字典中,则提供一个默认值

一:简单定制

classRoundFloatManual(object):def __init__(self, val):assert isinstance(val, float), "Value must be a float!"self.value= round(val, 2)>>> rfm =RoundFloatManual(42)

Traceback (mostrecent call last):

File"", line 1, in?

File"roundFloat2.py", line 5, in __init__assertisinstance(val, float), \ AssertionError: Value must be a float!>>> rfm =RoundFloatManual(4.2)>>>rfm

>>> printrfm

它因输入非法而异常,但如果输入正确时,就没有任何输出了。在解释器中,我们得到一些信息,却不是我们想要的。print(使用str())和真正的字符串对象表示(使用repr())都没能显示更多有关我们对象的信息。这就需要实现__str__()和__repr__()二者之一,或者两者都实现。加入下面的方法:

def __str__(self):return str(self.value)

现在我们得到下面的:

>>> rfm = RoundFloatManual(5.590464)>>>rfm

>>> printrfm5.59

>>> rfm = RoundFloatManual(5.5964)>>> printrfm5.6

但是在解释器中转储(dump)对象时,仍然显示的是默认对象符号,要修复它,只需要覆盖__repr__()。可以让__repr__()和__str__()具有相同的代码,但最好的方案是:__repr__ = __str__

在带参数5.5964的第二个例子中,我们看到它舍入值刚好为5.6,但我们还是想显示带两位小数的数。可以这样修改:

def __str__(self):return '%.2f' % self.value

这里就同时具备str()和repr()的输出了:

>>> rfm =RoundFloatManual(5.5964)>>>rfm5.60

>>>printrfm5.60

所有代码如下:

classRoundFloatManual(object):def __init__(self,val):assert isinstance(val, float), "Valuemust be a float!"self.value= round(val, 2)def __str__(self):return '%.2f' %self.value__repr__ = __str__

二:数值定制

定义一个Time60,其中,将整数的小时和分钟作为输入传给构造器:

classTime60(object):def __init__(self, hr, min):

self.hr=hr

self.min= min

1:显示

需要在显示实例的时候,得到一个有意义的输出,那么就要覆盖__str__()(如果有必要的话,__repr__()也要覆盖):

def __str__(self):return '%d:%d' % (self.hr, self.min)

比如:

>>> mon =Time60(10, 30)>>> tue =Time60(11, 15)>>>

>>> printmon, tue10:30 11:15

2:加法

Python中的重载操作符很简单。像加号(+),只需要重载__add__()方法,如果合适,还可以用__radd__()及__iadd__()。注意,实现__add__()的时候,必须认识到它返回另一个Time60对象,而不修改原mon或tue:

def __add__(self, other):return self.__class__(self.hr + other.hr, self.min + other.min)

在类中,一般不直接调用类名,而是使用self 的__class__属性,即实例化self 的那个类,并调用它。调用self.__class__()与调用Time60()是一回事。但self.__class__()的方式更好。

>>> mon = Time60(10, 30)>>> tue = Time60(11, 15)>>> mon +tue

>>> print mon +tue21:45

如果没有定义相对应的特殊方法,但是却使用了该方法对应的运算,则会引起一个TypeError异常:

>>> mon -tue

Traceback (mostrecent call last): File"", line 1, in?

TypeError:unsupported operand type(s)for -: 'Time60' and 'Time60'

3:原位加法

__iadd__(),是用来支持像mon += tue 这样的操作符,并把正确的结果赋给mon。重载一个__i*__()方法的唯一秘密是它必须返回self:

def __iadd__(self, other):

self.hr+=other.hr

self.min+=other.minreturn self

下面是结果输出:

>>> mon = Time60(10,30)>>> tue = Time60(11,15)>>>mon10:30

>>>id(mon)401872

>>> mon +=tue>>>id(mon)401872

>>>mon21:45

下面是Time60的类的完全定义:

classTime60(object):'Time60 - track hours and minutes'

def __init__(self,hr, min):'Time60 constructor - takes hours andminutes'self.hr=hr

self.min=mindef __str__(self):'Time60 - string representation'

return '%d:%d' %(self.hr, self.min)__repr__ = __str__

def __add__(self, other):'Time60 - overloading the additionoperator'

return self.__class__(self.hr + other.hr,self.min +other.min)def __iadd__(self,other):'Time60 - overloading in-place addition'self.hr+=other.hr

self.min+=other.minreturn self

4:升华

在这个类中,还有很多需要优化和改良的地方。首先看下面的例子:

>>> wed =Time60(12, 5)>>>wed12:5 #正确的显示应该是:“12:05”

>>> thu =Time60(10, 30)>>> fri =Time60(8, 45)>>> thu +fri18:75 #正确的显示应该是:19:15

可以做出如下修改:

def __str__(self):return '%02d:%02d'%(self.hr, self.min)__repr__ = __str__

def __add__(self, othertime):

tmin= self.min +othertime.min

thr= self.hr +othertime.hrreturn self.__class__(thr + tmin/60, tmin%60)def __iadd__(self, othertime):

self.min+=othertime.min

self.hr+=othertime.hr

self.hr+= self.min/60self.min%= 60

return self

三:迭代器

迭代器对象本身需要支持以下两种方法,它们组合在一起形成迭代器协议:

iterator.__iter__()      返回迭代器对象本身。

iterator.next()          从容器中返回下一个元素。

实现了__iter__()和next()方法的类就是一个迭代器。自定义迭代器的例子如下:

RandSeq(Random Sequence),传入一个初始序列,__init__()方法执行前述的赋值操作。__iter__()仅返回self,这就是如何将一个对象声明为迭代器的方式,最后,调用next()来得到迭代器中连续的值。这个迭代器唯一的亮点是它没有终点。代码如下:

classRandSeq(object):def __init__(self, seq):

self.data=seqdef __iter__(self):returnselfdefnext(self):return choice(self.data)

运行它,将会看到下面的输出:

>>> from randseq importRandSeq>>> for eachItem in RandSeq(('rock', 'paper', 'scissors')):

...printeachItem

...

scissors

scissors

rock

paper

paper

scissors

......

四:多类型定制

现在创建另一个新类,NumStr,由一个数字-字符对组成,记为n和s,数值类型使用整型(integer)。用[n::s]来表示它,这两个数据元素构成一个整体。NumStr有下面的特征:

初始化: 类应当对数字和字符串进行初始化;如果其中一个(或两)没有初始化,则使用0和空字符串,也就是, n=0 且s=''作为默认。

加法:   定义加法操作符,功能是把数字加起来,把字符连在一起;比如,NumStr1=[n1::s1]且NumStr2=[n2::s2]。则NumStr1+NumStr2 表示[n1+n2::s1+s2],其中,+代表数字相加及字符相连接。

乘法:  类似的, 定义乘法操作符的功能为, 数字相乘,字符累积相连, 也就是,NumStr1*NumStr2=[n1*n::s1*n]。

False 值:当数字的数值为 0 且字符串为空时,也就是当NumStr=[0::'']时,这个实体即有一个false值。

比较:  比较一对NumStr对象,比如,[n1::s1] vs. [n2::s2],有九种不同的组合。对数字和字符串,按照标准的数值和字典顺序的进行比较。

如果obj1< obj2,则cmp(obj1, obj2)的返回值是一个小于0 的整数, 当obj1 > obj2 时,比较的返回值大于0, 当两个对象有相同的值时, 比较的返回值等于0。

我们的类的解决方案是把这些值相加,然后返回结果。为了能够正确的比较对象,我们需要让__cmp__()在 (n1>n2) 且 (s1>s2)时,返回 1,在(n1s2),或相反),返回0. 反之亦然。代码如下:

classNumStr(object):def __init__(self, num=0, string=''):

self.__num =num

self.__string =stringdef __str__(self):return '[%d :: %r]' % (self.__num, self.__string)__repr__ = __str__

def __add__(self, other):ifisinstance(other, NumStr):return self.__class__(self.__num + other.__num, self.__string + other.__string)else:raise TypeError, 'Illegal argument type for built-in operation'

def __mul__(self, num):ifisinstance(num, int):return self.__class__(self.__num * num, self.__string *num)else:raise TypeError, 'Illegal argument type for built-inoperation'

def __nonzero__(self):return self.__num or len(self.__string)def __norm_cval(self, cmpres):returncmp(cmpres, 0)def __cmp__(self, other):return self.__norm_cval(cmp(self.__num, other.__num))+\

self.__norm_cval(cmp(self.__string,other.__string))

执行一些例子:

>>> a =NumStr(3, 'foo')>>> b =NumStr(3, 'goo')>>> c =NumStr(2, 'foo')>>> d =NumStr()>>> e =NumStr(string='boo')>>> f =NumStr(1)>>>a

[3 :: 'foo']>>>b

[3 :: 'goo']>>>c

[2 :: 'foo']>>>d

[0 ::'']>>>e

[0 ::'boo']>>>f

[1 :: '']>>> a

True>>> b

False>>> a ==a

True>>> b * 2[6 :: 'googoo']>>> a * 3[9 :: 'foofoofoo']>>> b +e

[3 :: 'gooboo']>>> e +b

[3 :: 'boogoo']>>> if d: 'not false'...>>> if e: 'not false'...'not false'

>>>cmp(a, b)-1

>>>cmp(a, c)1

>>>cmp(a, a)

0

如果在__str__中使用“%s”,将导致字符串没有引号:

return '[%d :: %s]' % (self.__num, self.__string)>>> printa

[3 :: foo]

第二个元素是一个字符串,如果用户看到由引号标记的字符串时,会更加直观。要做到这点,使用“repr()”表示法对代码进行转换,把“%s”替换成“%r”。这相当于调用repr()或者使用单反引号来给出字符串的可求值版本--可求值版本的确要有引号:

>>> printa

[3 :: 'foo']

__norm_cval()不是一个特殊方法。它是一个帮助我们重载__cmp__()的助手函数:唯一的目的就是把cmp()返回的正值转为1,负值转为-1。cmp()基于比较的结果,通常返回任意的正数或负数(或0),但为了我们的目的,需要严格规定返回值为-1,0 和1。

对整数调用cmp()及与 0 比较,结果即是我们所需要的,相当于如下代码片断:

def __norm_cval(self, cmpres):if cmpres<0:return -1

elif cmpres>0:return 1

else:return 0

两个相似对象的实际比较是比较数字,比较字符串,然后返回这两个比较结果的和。

本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_30849865/article/details/112989450。

该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。

作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。

如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。

相关阅读
文章标题:[转载][洛谷P1082]同余方程

更新时间:2023-02-18
[转载][洛谷P1082]同余方程
文章标题:[转载]webpack优化之HappyPack实战

更新时间:2023-08-07
[转载]webpack优化之HappyPack实战
文章标题:[转载]oracle 同时更新多表,在Oracle数据库中同时更新两张表的简单方法

更新时间:2023-09-10
[转载]oracle 同时更新多表,在Oracle数据库中同时更新两张表的简单方法
文章标题:[转载][Unity] 包括场景互动与射击要素的俯视角闯关游戏Demo

更新时间:2024-03-11
[转载][Unity] 包括场景互动与射击要素的俯视角闯关游戏Demo
文章标题:[转载]程序员也分三六九等?等级差异,一个看不起一个!

更新时间:2024-05-10
[转载]程序员也分三六九等?等级差异,一个看不起一个!
文章标题:[转载]海贼王 动漫 全集目录 分章节 精彩打斗剧集

更新时间:2024-01-12
[转载]海贼王 动漫 全集目录 分章节 精彩打斗剧集
名词解释
作为当前文章的名词解释,仅对当前文章有效。
特殊方法(魔术方法)在Python中,特殊方法是指那些以双下划线“__”作为前缀和后缀的方法,它们具有特殊含义,用于实现类的特定功能或与Python解释器进行交互。例如`__init__()`用于初始化对象,`__del__()`用于释放对象资源,`__str__()`和`__repr__()`分别定义对象的字符串表示形式。通过重载这些特殊方法,开发者可以自定义类的行为,如模拟标准类型、重载操作符以及控制属性访问等。
构造器构造器是面向对象编程中的一个重要概念,它指的是当创建一个类的新实例时所调用的方法。在Python中,构造器通常指`__init__()`方法,该方法在实例化对象时自动执行,用于设置对象的初始状态或执行必要的初始化操作。例如,在上述文章中,类`RoundFloatManual`中的`__init__(self, val)`就是构造器,用于接收浮点数并将其四舍五入为两位小数。
重载操作符重载操作符是指在面向对象编程中,重新定义或扩展某个操作符的行为。在Python中,可以通过实现对应的操作符特殊方法来重载操作符,比如实现`__add__()`方法以改变加法运算符"+"的行为。在示例类`Time60`中,通过覆盖`__add__()`方法使得两个时间对象相加时,会返回一个新的`Time60`对象,其小时和分钟之和为两个输入对象的相应值之和,这就是对加法操作符的重载。
延伸阅读
作为当前文章的延伸阅读,仅对当前文章有效。
在深入理解Python中特殊方法如何实现类的定制功能之后,我们可以进一步探索这一强大机制在实际开发中的应用。近期,随着Python 3.10版本的发布,官方对一些特殊方法进行了优化和新增,例如`__match__`方法用于支持模式匹配语法,使得代码更加简洁易读。此外,在数据科学领域,NumPy库通过自定义特殊方法实现了与Python内置类型无缝衔接的高性能数组运算,如`__array_ufunc__`方法允许用户控制NumPy如何处理用户自定义的数据类型。
而在软件工程实践中,特殊方法更是无处不在。比如Django框架内Model类的设计就大量运用了特殊方法,如`__str__`用于模型对象的字符串表示,`__getattr__`、`__setattr__`等用于属性管理,以及`save()`方法背后的`__init__`、`__new__`等构造逻辑。这些都充分体现了Python特殊方法在构建复杂系统时的重要性。
不仅如此,对于面向对象设计原则的理解,诸如封装、多态和继承,也能够在特殊方法的使用上得到生动体现。以重载比较操作符为例,通过实现`__eq__`、`__lt__`等方法,开发者能够根据业务需求为自定义类赋予灵活而精准的比较逻辑,从而实现更符合领域特性的行为表现。
总之,Python特殊方法不仅提供了丰富的扩展能力,还在不同场景下展现了其强大的灵活性和实用性。无论是跟进最新的Python语言特性更新,还是深入研究经典开源项目源码,或是解决实际编程问题,理解并熟练运用特殊方法都是提升Python编程水平的关键所在。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
grep -ir "search_text" . - 在当前目录及其子目录中递归搜索文本。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
基于Redis的分布式锁互斥性与可靠性实现及命名空间与原子性保障 04-22 可自定义刻度动画的jQuery进度条插件 02-07 jQuery和css3网站操作提示向导插件 12-28 jQuery创意响应式两栏滚动幻灯片特效 11-30 带视频播放的全屏轮播图布局特效 09-07 黑色炫酷个人摄影师网站通用模板下载 01-20 Cassandra中哈希分区与范围分区策略:数据分布、Murmur3Partitioner与负载均衡实践 11-17 [转载]java培训后好找工作吗 11-13 响应式环保包装盒设计公司网站静态模板 11-04 本次刷新还10个文章未展示,点击 更多查看。
中文建筑工程公司静态html网站模板下载 07-03 红色大气高端特色餐厅加盟网站模板 06-21 Vue.js 中的数据绑定与取消绑定:事件监听器、$destroy() 方法及 v-model 指令的运用与虚拟DOM、组件销毁的关系解析 06-20 响应式游戏应用商店单页网站html模板 06-15 自考大学通用模板下载 06-13 jqtimeline.js-简单又好用的jquery时间轴插件 06-04 [转载]Java Work 05-26 红色简洁电影售票平台网站html模板 05-02 投资集团项目展示页面网站HTML5模板 03-22 soulmate粉色干净浪漫唯美婚礼单页响应式网站模板 03-07 页面滚动时动态为元素添加class的jQuery插件 03-05
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"