IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 面对对象编程细则(三) -> 正文阅读

[Python知识库]面对对象编程细则(三)


前面两篇内容,我们已经介绍了很多实用的面对对象编程技巧,这一节我们继续补充一些概念。对于这些概念大多只需要我们知道即可:

抽象基类

在定义一组类的继承层次结构时,避免重复代码的技术之一是设计一个基类,该基类可以被需要他的其他类所继承。然而,如果以各类唯一目的就是作为继承的基类,这个类既可以叫做抽象基类。更正式地说,一个抽象类不能直接实例化,因为它可以是没有任何实际意义的类。因为python由于对声明类型没有做强制要求,这种多态性也自然让python对定义正式的抽象基类没有强烈的要求。也因此我们编程中,对抽象基类的应用也不多见。但是python依然提供了一个abc模块定义了抽象基类:
在这里插入图片描述
我们来看一个例子:

from abc import abstractmethod,ABCMeta
class Seq(metaclass=ABCMeta):
    @abstractmethod
    def __len__(self):
        '''返回接受列表的长度'''

在这个例子中,我们定义了一个__len__()方法,可以看到我们注释了该方法所实现的功能,然而其内部却没有任何实现。这是因为在该方法声明前,我们使用了@abstractmethod声明了这个方法是抽象的,不需要再Seq类中提供实现,我们希望这个方法在继承该类的子类中提供实现。

深拷贝和钱拷贝

拷贝是一个非常常见的内容,在C语言中,我们只需要定义两个不同的变量名,再将一个标识符内容直接复制给另一个,就可以较好地完成拷贝,然而在python基础补充中我们提到过,如果按以下定义:

a=[1,2,3,4,5]
b=a
# a和b的实际地址是一样的,只是给一个内容起了两个别名,
# 并不是创立一个新的列表
b.append(6)
print(a)
# 输出为:[1, 2, 3, 4, 5, 6]

显然这样的结果显然不符合我们的预期。那么在Python中如何完成拷贝呢?

浅拷贝

浅拷贝的表达方式很简单,我们只需要做以下操作:

a=[1,2,3,4,5]
b=list(a)
b.append(6)
print(a)
# 输出为:[1, 2, 3, 4, 5]

看起来这样就满足要求了。其原理如下:
在这里插入图片描述
这是一维列表的情况,看起来已经满足了我们的要求。下面我们拟想另一种情况,我们建立一个二维列表,每个元素存储一个学生的三科成绩,并且不需要注明是哪位学生的成绩:

a=[[70,65,92],[88,84,73],[60,60,60]]
b=list(a)

大家猜猜拷贝的情况是什么样呢?
在这里插入图片描述
如果我们想要给b列表再加一列,是不会影响a的:

a=[[70,65,92],[88,84,73],[60,60,60]]
b=list(a)
b.append([62,100,91])
print(a,'\n',b)
# 输出为:[[70, 65, 92], [88, 84, 73], [60, 60, 60]] 
#         [[70, 65, 92], [88, 84, 73], [60, 60, 60], [62, 100, 91]]

原因如下:
在这里插入图片描述
因此,如果我们通过以下方式修改b[0]的内容:

a=[[70,65,92],[88,84,73],[60,60,60]]
b=list(a)
b.append([62,100,91])
del (b[0])[1] # 删除b[0]列表中的第二个元素
b[0].insert(1,72) # 将b[0]列表中第二个元素改为72
# 以上两行也可以直接写成:
# b[0][1]=72
print(a,'\n',b)
# 输出为:[[70, 72, 92], [88, 84, 73], [60, 60, 60]] 
#         [[70, 72, 92], [88, 84, 73], [60, 60, 60], [62, 100, 91]]

就会发现,通过b修改a和b列表重叠部分的元素时,依然会对a造成影响。
如果想要从根本上解决这个问题,就需要用到深拷贝。

深拷贝

python给我们提供了一个拷贝的模块即copy,这个模块可以帮助我们实现真正的拷贝即深拷贝。深拷贝可以让上例a和b成为完全独立的部分:

import copy
a=[[70,65,92],[88,84,73],[60,60,60]]
b=copy.deepcopy(a)
b.append([62,100,91])
b[0][1]=72
print(a,'\n',b)
# 输出为:[[70, 65, 92], [88, 84, 73], [60, 60, 60]] 
#         [[70, 72, 92], [88, 84, 73], [60, 60, 60], [62, 100, 91]]

此时a和b的关系就是独立的:
在这里插入图片描述

运算符重载和python的特殊方法

Python的内置类为许多操作提供了自然的语义。比如,a+b语句可以调用数值类型语句,也可以连接序列类型。当定义一个新类时,我们必须考虑到当a或者b是类中的实例时是否应该定义类似于a+b的语句。
默认情况下,对于新的类来说,“+”操作符是未定义的。然而,类的作者可通过操作符重载(operator overloading)技术来定义它。这个定义可通过一个特殊的命名方法来实现。特别的是,名为__add__的方法重载+操作符,__add__用右边的操作作为参数并返回表达式的结果。也就是说,a+b语句,被转换为一个调用a.__add(b)对象的方法。类似的特殊命名方法存在其他操作符中。表2-1提供了与这一方法类似的完整列表。
表2-1 用Python特殊方法实现的重载操作

常见语法特别方法的形式
a+ba._add _(b)或 b._radd _(a)
a-ba._sub _(b)或b._rsub _(a)
a*ba._mul _(b)或b._rmul _(a)
a/ba._truediv _(b)或b._rtruediv _(a)
a//ba._floordiv _(b)或b._rfloordiv _(a)
a%ba.__ mod_ _(b);或b._rmod _(a)
a**ba._pow _(b)或b._rpow _(a)
a<<ba._lshift _(b);或b._rlshift _(a)
a>>ba._rshift _(b);或b._rrshift _(a)
a&ba._and _(b);或b._rand _(a)
a^ba._xor _(b);或b._rxor _(a)
ab
a+=ba._iadd _(b)
a-=ba._isub _(b)
a*=ba._imul _(b)
+aa._pos _(b)
-aa._neg _(b)
~aa._inwert _(b)
abs(a)a._abs _(b)
a<ba._lt _(b)
a<=ba._le _(b)
a>ba._gt _(b)
a>=ba._ge _(b)
a==ba._eq _(b)
a!=ba._ne _(b)
vinaa._contains _(v)
a[k]a._getitem _(k)
a[k]=va._setitem _(k,v)
dela[k]a._delitem _(k)
a(arg1,arg2,…)a._call _(arg1,arg2,…)
len(a)a._len _()
hash(a)a._hash _()
iter(a)a._iter _()
next(a)a._next _()
bool(a)a._bool _()
float(a)a._float _()
int(a)a._int _()
repr(a)a._repr _()
reversed(a)a._reversed _()
str(a)a._str _()

当一个二元操作符应用于两个不同类型的实例中时,Python对根据左操作数的类进行判断。在这个例子中,对于使用__mul__方法把字符串与实例相乘,可以通过检查int类是否提供了相应的定义。然而,如果这个类没有实现这一行为,Python就会以一种名为 rmul(即“右乘”)的特殊方法来检查右操作数的类的定义。该方法为新用户定义的类提供了一个支持包含已存在类(所给的已存在的类可能没有定义引用该新类的行为)的实例的混合操作的方法。__mul__和__rmul__的区别也允许类根据情况定义不同的语义,如操作数在矩阵乘法中就是不可交换的。
到此为止,面对对象编程的细则已经给大家补充了很多了,后面我们再介绍数据结构时可能还会补充另外一些细则,大家记得追更~

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-05-11 16:25:25  更:2022-05-11 16:25:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 19:01:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计