![0da9468ed2a8b7c6d60328da7c9274ef.png](https://i-blog.csdnimg.cn/blog_migrate/915431ade0395304c8e19831fb30c158.jpeg)
本章重点内容:
1、基础知识
2、索引和分片:__getitem__和__setitem__
3、索引迭代:__getitem__
4、可迭代对象:__iter__和__next__
5、属性访问:__getattr__和__setattr__
6、字符串显示:__repr__和__str__
7、右侧加法和原位置加法:__radd__和__iadd__
8、调用表达式:__call__
9、比较运算:__lt__、__gt__和其他方法
10、布尔测试:__bool__和__len__
11、对象析构函数:__del__
接下来针对以上内容进行详细的说明,如下:
1、基础知识
运算符重载,意味着在某个类的方法中拦截内置的操作,当类的实例出现在内置操作中时,Python会自动调用你的方法,并且你的方法的返回值会作为相应操作的结果,
1)运算符重载让类拦截常规的Python操作
2)类可重载所有Python表达式运算符
3)类也可重载打印、函数调用、属性访问等内置运算
4)重载使类实例的行为更接近内置类型
5)重载是通过在一个类中提供特殊名称的方法来实现的
我们通过一个简单的例子来看下构造函数(__init__)和表达式(__sub__)的运算符重载,来理解上面的内容,具体代码如下:
![00cd11f6becef3c6ee6369d2ffc88be5.png](https://i-blog.csdnimg.cn/blog_migrate/c5f7950439e03d7114f893f042fee7de.png)
常见的运算符重载方法还有很多,接下来择取重点且常见的说明,至于有哪些或者多少运算符重载方法,可以百度查看,书上列表中,已经列明了至少27类,其他的应该还有
2、索引和分片:__getitem__和__setitem__
我们先来看索引和分片的运算符重载,当实例X出现在X[i]这样的索引运算中时,Python会调用这个实例继承的__getitem__方法,把X作为第一位参数传入,并且将方括号内的索引值传递给第二个参数,具体代码如下:
![02961374d04842671b9a16b3066e4275.png](https://i-blog.csdnimg.cn/blog_migrate/e4f0c95d4b0a425cdc91a4a6f85fda8d.png)
__getitem__是查看类属性的值,可以通过索引,而__setitem__是更新类属性的值,主要是针对有键值对的,具体代码实例如下:
![add9aa194842427405f1515dd0d2742a.png](https://i-blog.csdnimg.cn/blog_migrate/339d586ab4228decf4e78d73aae9abf3.png)
3、索引迭代:__getitem__
也就是说,如果有该方法存在,那该类的对象,是可迭代的,例如,承接上面的例子,可以通过list()函数直接查看实例X中的内容
![03fca13abfb84cf498097e8b77fb8d30.png](https://i-blog.csdnimg.cn/blog_migrate/e92287007f35f9c4249d3f402748ff7d.png)
在这里是一个概念或者说技巧,后续在使用中可考虑
4、可迭代对象:__iter__和__next__
虽然上面说的__getitem__可用,但是Python中所有的迭代上下文都会先尝试__iter__方法,再尝试__getitem__,也就是说我们应该优先调整__iter__方法
通过__iter__和__next__方法的结合使用,可以实现类实例的迭代,具体代码如下:
![96f7e7dfb1642ec3d8fe9f097cc1c36c.png](https://i-blog.csdnimg.cn/blog_migrate/cae1fd4924503f9ca260387ce95f54d5.png)
以上是创建了一个类,接下来通过实例来使用迭代功能
![0ff8df98e36b6c086899cf9aee7b4095.png](https://i-blog.csdnimg.cn/blog_migrate/8b0d7f143fa8c486481183c8ddd11001.jpeg)
5、属性访问:__getattr__和__setattr__
__getattr__是访问属性,__setattr__是修改属性
先创建一个简单的类,如果要访问不存在的属性,系统会出现提示信息,具体代码如下:
![e16c0733ad2971419cd744d3c1f07456.png](https://i-blog.csdnimg.cn/blog_migrate/b32b2545041c72591a14e8c0f1a3eab7.jpeg)
对于类,如果你直接添加属性和值是可以的,但是可以通过__setattr__来屏蔽,还是承接上面代码的实例,代码调整如下:
![1a5ffe58879f30ec4405fe556c375d33.png](https://i-blog.csdnimg.cn/blog_migrate/7cceeaf4364ffc3eba04065ee6311b7e.png)
对于以上代码,运行结果如下:
![ee7d8885ad24c5c53155121ecebafa3b.png](https://i-blog.csdnimg.cn/blog_migrate/8286044bee4da4537549d082d1e723fd.jpeg)
6、字符串显示:__repr__和__str__
关于字符串显示,前面章节中有说明,也有用到__repr__来设计打印类的结果,那与__str__有什么区别呢?
__str__:会首先被打印操作和str内置函数尝试(print运行的内部等价形式),它通常应当返回一个用户友好的显示
__repr__:用于所有其他的场景,如果没有定义__str__则打印操作也会使用__repr__,也就是说可以用于任何地方
通过以下代码,会更好的说明这一点:
首先,看下,如果没有定义__str__和__repr__的情况下会是什么情况
![71ca0c4bea34364cf26c5d93d7522aaa.png](https://i-blog.csdnimg.cn/blog_migrate/0a504b76f67d3bc510a1b8764a0bd4c4.png)
你会发现,直接调用实例或者打印实例,都是显示一串代码,它是说明该实例的内存地址
如果先定义__repr__,看下结果:
![8add8a8449a5f198834f57bc58f52f74.png](https://i-blog.csdnimg.cn/blog_migrate/b240da927d1d880c98e99e524117f405.png)
再定义__str__看下结果:
![74bd5479e2200ccec2d31d020252d888.png](https://i-blog.csdnimg.cn/blog_migrate/332f418398f70e740f043bd5d14d0c58.png)
7、右侧加法和原位置加法:__radd__和__iadd__
常规定义的__add__一般都是右侧加法,也就是相加的对象在实例的右侧,如果是左侧,系统会提示错误,具体代码示例如下:
![198b6316fd6f5891d2bd35da72969faf.png](https://i-blog.csdnimg.cn/blog_migrate/b7a3ce4b11d14713980175def8b8acaa.jpeg)
通过定义__radd__来解决这个问题
![fb14d593fc2cc31b3fff0ac58c7887c2.png](https://i-blog.csdnimg.cn/blog_migrate/0a6e51c8a51ac483bc1b629693f9559d.png)
如果要实现【+=】这种原位置加法,可以通过__iadd__来定义,具体代码示例如下:
![19925891c961a31efefbc0c5f2c71473.png](https://i-blog.csdnimg.cn/blog_migrate/95bcc14b16d60bc94be1b7d37930a7c8.png)
8、调用表达式:__call__
通过定义__call__可以实现实例不同的调用,具体代码如下:
![56903cfb4dc3ee7b8c16da2f1a29f5f2.png](https://i-blog.csdnimg.cn/blog_migrate/8c0c421ac4a3bd1260c8f67705bac580.png)
9、比较运算:__lt__、__gt__和其他方法
这个比较容易理解,就是如果实例与其他比较时,如何处理,具体代码说明如下:
![539eb852ab1a737dcf74aab05f40f240.png](https://i-blog.csdnimg.cn/blog_migrate/57306e98468d40be73dab37fe7143754.png)
10、布尔测试:__bool__和__len__
Python会首先尝试__bool__来获取一个直接的布尔值,如果没有该方法,就退而求其次的尝试__len__来根据对象的长度确定真值,
系统默认实例对象是真的,如果需要我们特殊的处理,可以通过这个定义不一样的结果,
先看系统默认的情况:
![e3f6fa3f643bd53a012d7a98cae22fb1.png](https://i-blog.csdnimg.cn/blog_migrate/614b33fb6f35d39255fc9b399b7188c6.png)
定义新的结果:
![53af3f0fdc1fe55e24c4c6b9f4514acb.png](https://i-blog.csdnimg.cn/blog_migrate/1231942f3c3b275bc8cfa076f422d82d.png)
11、对象析构函数:__del__
我们知道实例创建的时候会调用__init__来创建,如果实例空间被回收时,就会调用__del__,一般来说,系统是自动调用完成的,在此我们可以了解这个如何运作的,析构函数一般不常用,但是很重要
具体代码示例如下:
![faaa435e70b9267940b84636e6cc7fcb.png](https://i-blog.csdnimg.cn/blog_migrate/d3819c6d199dac324bc1e455323f3521.png)
本文为作者手打原创,如有引用请取得作者同意
说明:本章内容基于《Python学习手册 第五版》内容学习整理