Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在不使用外部模块的情况下重载类的pythonic方法是什么?_Python_Python 3.x_Oop_Math - Fatal编程技术网

在不使用外部模块的情况下重载类的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”类型的非整数相乘

否。Python不支持重载,
@重载
装饰器仅用于类型检查器(仅实际执行该方法的最后一个实现)。您的方法在我看来很好。
对象
是正确的注释;运算符重载应该接受任意其他操作数,如果它们得到一个不理解的参数,则返回
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')