python mul_流畅的python学习笔记:第十三章:重载运算符__add__,__iadd__,__radd__,__mul__,__rmul__,__neg__,__eq__,__inver...

本文详细介绍了Python中运算符重载的使用,包括`__neg__`、`__pos__`、`__invert__`等方法的实现,以及`__add__`、`__iadd__`在向量相加中的应用,涉及到`zip`、`itertools.izip_longest`和向量与列表的兼容性处理。此外,还讨论了`__eq__`和增量赋值运算符`+=`的实现细节。
摘要由CSDN通过智能技术生成

在前面第十章以及第一章的时候介绍了Vector对象的运算符重载。第十三章专门介绍运算符重载。这里我们看几个之前没讲过的运算符__neg__,__pos__,__invert__

classVector(object):

def__init__(self,x):

self.x=x

def__neg__(self):

return "Vector(%d)"% (-self.x)

def__str__(self):

return "Vector(%s)"% (str(self.data))

def__iter__(self):

returniter(self.data)

def__pos__(self):

return "Vector(%d)"% (self.x+1)

def__invert__(self):

return "Vector(%d)"% (~self.x)

if__name__=="__main__":

v=Vector(1)

print-v

print+v

print~v

E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter13.py

Vector(-1)

Vector(2)

Vector(-2)

__neg__是在-v的时候调用

__pos__是在+v的时候调用

__invert__是在~v的时候调用

下面我们重新来看下+运算符。我们想实现两个向量想加Vector([1,2,3])+Vector([1,2,3])得到[2,4,6].代码如下

classVector(object):

def__init__(self,x):

self.x=x

def__add__(self, other):

return[a+b fora,b inzip(self.x,other.x)]

if__name__=="__main__":

v1=Vector([1,2,3])

v2=Vector([1,2,3])

printv1+v2

E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter13.py

[2, 4, 6]

在前面的例子中通过zip函数对两个列表进行配对得到元组。[(1,1),(2,2),(3,3)]然后迭代进行加法运算最终得到结果[2,4,6]

但是如果两个向量的格式变化一下。变成Vector([1,2,3])+Vector([1,2,3,4]).我们期望得到Vector([2,4,,6,4]), 向量Vector([1,2,3,4])由于比Vector([1,2,3])多一个数字,想加的时候最好是用零填充较短的那个向量。那么实际结果如何呢

if__name__=="__main__":

v1=Vector([1,2,3])

v2=Vector([1,2,3,4])

printv1+v2

E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter13.py

[2, 4, 6]

我们看到结果和上次一样还是[2,4,6]和我们预想的[2,4,6,4]相差太大。原因在于zip得到的结果是[(1, 1), (2, 2), (3, 3)],并没有包含多出来的4。这种情况下我们就需要用到itertools.izip_lonest,这个方法会自动填充缺失的向量元素

classVector(object):

def__init__(self,x):

self.x=x

def__add__(self, other):

pairs=itertools.izip_longest(self.x,other.x,fillvalue=0)

return[a+b fora,b inpairs]

if__name__=="__main__":

v1=Vector([1,2,3])

v2=Vector([1,2,3,4])

printv1+v2

E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter13.py

[2, 4, 6, 4]

在izip_longest中,fillvalue代表填充的值。本次例子中设置的是0.因此最后一位是0+4=4

接下来我们的需求继续变下。我们想实现Vector([1,2,3])+[1,2,3]也就是向量类和列表相加

classVector(object):

def__init__(self,x):

self.x=x

def__add__(self, other):

iftype(other) == list:

pairs=itertools.izip_longest(self.x,other,fillvalue=0)

else:

pairs=itertools.izip_longest(self.x,other.x,fillvalue=0)

return[a+b fora,b inpairs]

if__name__=="__main__":

v1=Vector([1,2,3])

v2=Vector([1,2,3,4])

printv1+[1,2,3,4]

E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter13.py

[2, 4, 6, 4]

首先在__add__中判断other的属性,然后针对性的得到pairs

那如果是[1,2,3,4]+v1的结果会是什么呢?运行报错。

E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter13.py

Traceback (most recent call last):

File "E:/py_prj/fluent_python/chapter13.py", line 27, in

print [1,2,3,4]+v1

TypeError: can only concatenate list (not "Vector") to list

这是因为[1,2,3,4]并没有add方法,只有Vector才有,这种场景需要用到__radd__方法

具体的运算流程图如下:

1 如果a有__add__方法,则进行a.__add__(b)运算,否则返回Notimplemented然后检查b有没有__radd__方法。如果有,则调用b.__radd__(a),否则返回Notimplemented

我们在Vector中增加__radd__方法:

def__radd__(self, other):

returnself+other

__radd__直接委托__add__进行运算。代码也很简单。这下运算结果正确了。

E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter13.py

[2, 4, 6, 4]

同样的方法也适用于乘法运算符__mul__和__rmul__。

下面来看下比较运算符以及反向比较在__eq__的作用。

首先定义__eq__的代码,首先比较长度,然后比较对应的元素,如果都相等则返回True,否则返回False

def__eq__(self, other):

iftype(other) == list ortype(other)==tuple:

pairs=itertools.izip_longest(self.x,other,fillvalue=0)

length=len(other)

else:

pairs=itertools.izip_longest(self.x,other.x,fillvalue=0)

length=len(other.x)

return(len(self.x)==length) andall(a==b fora,b inpairs)

if__name__=="__main__":

v1=Vector([1.0,2.0,3.0])

v2=Vector(range(1,4))

print 'v1 compare v2 %s'% (v1==v2)

v3=(1,2,3)

print 'v1 compare v3 %s'% (v1==v3)

E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter13.py

v1 compare v2 True

v1 compare v3 True

v1和v2相等这个没啥疑问,但是当用元组(1,2,3)和向量v1相比的时候,得到的结果也是True,我们如果用[1,2]==(1,2)得到的结果为False,因为列表和元组不是一个类型。那么为什么向量和元组相比却是相等的呢? 这就是问题所在了。在比较的时候并没有比较类型。代码更新如下:

def__eq__(self, other):

iftype(other) == list ortype(other)==tuple:

pairs=itertools.izip_longest(self.x,other,fillvalue=0)

length=len(other)

else:

pairs=itertools.izip_longest(self.x,other.x,fillvalue=0)

length=len(other.x)

ifisinstance(other,Vector): #在这里判断是否属于向量类return(len(self.x)==length) andall(a==b fora,b inpairs)

else:

returnNotImplemented

再继续看一个例子,增加一个Vector2d向量:

classVector2d(object):

def__init__(self,x):

self.x=x

def__eq__(self, other):

returntuple(self.x) ==  tuple(other.x)

if__name__=="__main__":

v1=Vector([1.0,2.0,3.0])

v4=Vector2d([1,2,3])

printv1==v4

E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter13.py

True

得到的结果为True. Vector2d不属于Vector的实例呢。为什么会相等呢。这里用到了反向比较的方法

(1)首先Vector.__eq__(v1,v4),v4不是Vector的实例。返回Notimplemented。然后尝试调用Vector2d.__eq__(v4.v1)

(2)Vector2d.__eq__(v4.v1)把两个操作数都变成元组。然后比较。结果为True。

其实在用Vector和元组进行比较的时候,也是一样的首先Vector.__eq__(v1,v4),返回Notimplemented。接着开始调用tuple.__eq__(v3,v1),但是tuple不知道vector是什么,因此返回Notimplemented。对于==来说,如果反向调用也是Notimplemented,则会进行最后的尝试,比较对象的ID,如果仍然不相等则返回False。

接下来我们看下!=运算符

printv1!=v4

得到的结果是True,但是我们并没有实现__neq__的方法,也能得到对应的结果,其实__neq__不用实现,只要定义了__eq__的方法,__neq__则会自动对__eq__的结果取反。

最后来看下增量赋值运算符:

if__name__=="__main__":

v1=Vector([1.0,2.0,3.0])

printid(v1)⑴v2=Vector(range(1,4))

v1+=v2⑵printv1

printid(v1)⑶

E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter13.py

25012400

[2.0, 4.0, 6.0]

25005672

在(1)中,得到的id(v1)=25012400。

在(2)中,经过v1+=v2后。在(3)中打印id(v1)等于25005672.和之前第一步的不一样了,也就是创建了新的实例。

如果我们想实现就地运算,不生成新的实例,就在v1的基础上想加呢。这就需要实现__iadd__方法。当执行+=的时候会自动调用__iadd__方法,而如果没有实现__iadd__方法,则会自动调用__add__方法

def__iadd__(self, other):

iftype(other) == list:

pairs=itertools.izip_longest(self.x,other,fillvalue=0)

else:

pairs=itertools.izip_longest(self.x,other.x,fillvalue=0)

i=0

forp inpairs:

self.x[i]=p[0]+p[1]

i+=1

returnself

在__iadd__方法中,返回的是self. 再来看下执行结果:

E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter13.py

25274544

Vector([2.0, 4.0, 6.0])

25274544

得到的实例是同一样

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值