在不使用外部模块的情况下重载类的pythonic方法是什么?
考虑以下类别:在不使用外部模块的情况下重载类的pythonic方法是什么?,python,python-3.x,oop,math,Python,Python 3.x,Oop,Math,考虑以下类别: class Vector2(): def __init__(self, x: float = 0, y: float = 0) -> None: self.x = x self.y = y 在本例中,我将如何覆盖\uuuuuuuuuuuuuuuuuuu,以便它可以同时使用标量和另一个向量2 我最初的方法是使用isinstance函数来检查我使用的另一个变量是int还是float。这是可行的,但是,将isinstance函数与一组el
class Vector2():
def __init__(self, x: float = 0, y: float = 0) -> None:
self.x = x
self.y = y
在本例中,我将如何覆盖\uuuuuuuuuuuuuuuuuuu,以便它可以同时使用标量和另一个向量2
我最初的方法是使用isinstance函数来检查我使用的另一个变量是int还是float。这是可行的,但是,将isinstance函数与一组else if一起使用看起来并不理想
def __mul__(self, other: object) -> Vector2:
if isinstance(other, int) or isinstance(other, float):
return Vector2(self.x * other, self.y * other)
elif isinstance(other, Vector2):
return Vector2(self.x * other.x, self.y * other.y)
else:
return NotImplemented
Python确实有一个允许“重载”的内置模块,还有一些模块也可以解决这个问题
在这种情况下,有没有更干净的方法呢?对于isinstance(other,(int,float))
您可以使用捕获所有数字类型,而不管具体实现如何
import numbers
...
isinstance(other, numbers.Number)
或
这样,您就不必指定它是int
还是float
或其他类似的值
至于你的问题,在这种情况下,我看不出一堆if-else
,有什么不对,但是如果你想要标准库也有这样的东西:(py 3.4+)和(py 3.8+)在幕后基本上是一样的
编辑
为了不需要在类之外定义others方法,这样您就可以检查这个类的分派,您可以定义一个基类,它可以实现一些基本的东西,而您的主类可以从中继承并实现重要的东西
from functools import singledispatchmethod
from numbers import Real
class BaseVector2():
def __init__(self, x: Real = 0, y: Real = 0) -> None:
self.x = x
self.y = y
def __str__(self):
return f"{self.__class__.__name__}(x={self.x}, y={self.y})"
class Vector2(BaseVector2):
@singledispatchmethod
def __mul__(self, other):
return NotImplemented
@__mul__.register
def _(self,other:Real):
print("numbers")
return Vector2(self.x * other, self.y * other)
@__mul__.register
def _(self,other:BaseVector2):
print("vector")
return Vector2(self.x * other.x, self.y * other.y)
样本使用
>>> x = Vector2(3, 2)
>>> y = Vector2(2, 2)
>>> print(x*2.5)
numbers
Vector2(x=7.5, y=5.0)
>>> print(x*2)
numbers
Vector2(x=6, y=4)
>>> print(x*y)
vector
Vector2(x=6, y=4)
>>> print(x*"boo")
Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
print(x*"boo")
TypeError: can't multiply sequence by non-int of type 'Vector2'
>>>
>x=Vector2(3,2)
>>>y=矢量2(2,2)
>>>打印(x*2.5)
数字
矢量2(x=7.5,y=5.0)
>>>打印(x*2)
数字
向量2(x=6,y=4)
>>>打印(x*y)
矢量
向量2(x=6,y=4)
>>>打印(x*“boo”)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
打印(x*“boo”)
TypeError:无法将序列与“Vector2”类型的非整数相乘
>>>
我最终使用了(仅适用于python 3.8+)
我们在主类中修饰一个默认函数,然后添加它们的实现
利用
@cls.f.寄存器
其中,cls
是类名,f
是函数名
现在,输入这个
x = Vector2(3, 2)
y = Vector2(2, 2)
print(x * y)
print(x * 2)
print(x * 2.5)
print(x*'a')
返回
- 我是一个向量
- 我是一个整数
- 我是一个浮子
- TypeError:无法将序列与“Vector2”类型的非整数相乘
@重载
装饰器仅用于类型检查器(仅实际执行该方法的最后一个实现)。您的方法在我看来很好。对象
是正确的注释;运算符重载应该接受任意其他操作数,如果它们得到一个不理解的参数,则返回NotImplemented
(因此else
的大小写应该是returnnotimplemented
,而不是raise…
)。次要说明:如果是instance(other,(int,float))则可以将第一次检查压缩为:
;如果给它一个类型的元组
,如果它是其中任何一个类型的实例,它将返回true。是否应还原上次编辑?对于新阅读此问题并稍后检查注释的人来说,如果没有查看编辑历史记录,谈论与使用或的原始注释相比,如果isinstance(other,(int,float))
发生此更改,注释就没有意义。是的,我想是这样的。。。从某种意义上说,数字更具可读性。数字几乎总是错误的。几乎没有任何东西真正适用于任意Number
s,除非它确实适用于任意对象。特别是,不能保证向量可以用任意的数字乘以self.x
和self.y
。Number
模块几乎完全没有用处。@user2357112supportsMonica怎么回事?这里的要点很简单,要知道你得到的是一个数字类型,而不关心具体的数字,如果你不喜欢数字.Number
,那么就使用数字.Real
,或者别的什么,只是为了避免再次需要列出具体的一个…但你确实需要知道具体的情况。例如,您将接受Decimal
视为一件好事,但不能将Decimal
和float
相乘。Number
的任意实例不可互操作。知道一个对象是一个数字
并不意味着你知道的足够多,可以用它做任何有用的事情。我看不出这里有什么问题-是的,不同的数字类型是不可互操作的,在这种情况下,如果你这样做,你会得到一条异常消息告诉你。但很有可能,一个程序中的所有向量都有相同类型的数字。如果是为了一个可重用的库,那么对数字类型更加宽容意味着一个用户可以有浮点向量,另一个用户可以有小数向量,两者都可以工作。如果有人混合了浮点数和小数,那么无论哪种方式,他们都会得到一个错误。我会更新我的答案,以显示在类中执行该操作的方法
class Vector2():
def __init__(self, x: float = 0, y: float = 0) -> None:
self.x = x
self.y = y
@singledispatchmethod
def __mul__(self, other):
return NotImplemented
@Vector2.__mul__.register
def _(self, other: Vector2):
print("I'm a vector")
# return Vector2(self.x * other.x, self.y * other.y)
@Vector2.__mul__.register
def _(self, other: int):
print("I'm an int")
# return Vector2(self.x * other, self.y * other)
@Vector2.__mul__.register
def _(self, other: float):
print("I'm a float")
# return Vector2(self.x * other, self.y * other)
x = Vector2(3, 2)
y = Vector2(2, 2)
print(x * y)
print(x * 2)
print(x * 2.5)
print(x*'a')