什么是最符合Python风格的方法来检查一个对象是否是一个数字?

27 浏览
0 Comments

什么是最符合Python风格的方法来检查一个对象是否是一个数字?

对于任意的Python对象,要判断它是否为数字,最好的方法是什么?这里\"是\"的定义是\"在某些情况下表现得像一个数字\"。\n例如,假设你正在编写一个向量类。如果给定另一个向量,你想要找到点积。如果给定一个标量,你想要缩放整个向量。\n检查是否为int、float、long、bool很麻烦,而且不能涵盖可能表现得像数字的用户定义对象。但是,仅仅检查__mul__是不够的,因为刚刚描述的向量类会定义__mul__,但它不是我想要的那种数字。

0
0 Comments

这是一个很好的例子,异常处理在这里非常适用。只需像处理数字类型一样操作,然后捕获其他类型的TypeError异常。

但显然,这只是检查操作是否“可行”,而不是检查操作是否“合理”!唯一真正的解决方法是永远不要混合不同类型,并始终确切知道您的值属于哪个类型类。

对于鸭子类型的+1:我关心的不是我的数据是什么类型,而是我是否可以按照我想要的方式使用它。

这曾经是传统的方法,但为了摆脱纯粹的鸭子类型,并在许多情况下使isinstance实际上变得有用(包括“检查是否合理”以及操作的形式适用性),ABCs已被引入。对于长期只使用Python的人来说,这是一个很困难的转变,但这是Python哲学中一个非常重要且微妙的趋势,忽视它将是一个严重的错误。

:对类型类(主要是collections.Sequence和相关类)的支持表示我赞同鸭子类型。但据我所知,没有这样的类适用于数字、向量或任何其他数学对象。

我认为在这种情况下鸭子类型并不是一个好的解决方案。想象一下,如果我有一个可能包含数字或序列的嵌套结构。我想要对数字进行相加。可惜,序列也可以进行“相加”,但(1,) + (3,)显然不等于1 + 3

0
0 Comments

在Python中,我们经常需要判断一个对象是否是数字。但是,对于不同的上下文,"数字"的定义可能有所不同。在Python2.5及更早的版本中,唯一的方法是检查一些特定情况并进行判断。然而在Python2.6及更高版本中,我们可以使用`isinstance`函数与`numbers.Number`这个抽象基类(ABC)进行判断,该ABC就是专门为这个目的而存在的。

如果需要在Python2.5及更早的版本中进行判断,有时可以使用"能够与0相加且不可迭代"的定义进行判断。但是,我们需要仔细考虑我们认为"数字"必须能够做什么以及绝对不能做什么,并进行相应的检查。

在Python2.6及更高版本中,可能还需要使用`numbers.Number`进行自定义类型的注册,以添加自己关心的类型。如果你想要排除一些声称自己是数字但你不能处理的类型,这需要更加小心。由于抽象基类没有`unregister`方法,你可以创建自己的抽象基类`WeirdNum`,在其中注册所有这些对于你而言奇怪的类型,然后首先检查是否为`WeirdNum`的实例,如果是则放弃检查,否则继续检查是否为`numbers.Number`的实例。

另外,如果你需要检查一个对象`x`是否能够做某些事情,通常你需要尝试类似以下的代码:

try:
    0 + x
except TypeError:
    canadd=False
else:
    canadd=True

仅仅通过`__add__`方法的存在与否并不能提供有用的信息,因为所有序列都有这个方法,用于与其他序列进行连接。这个检查等价于"数字是一种使得该类型的序列作为`sum`内置函数的有效单个参数的东西"的定义。完全奇怪的类型(例如,当与0相加时抛出"错误"异常的类型,例如`ZeroDivisionError`或`ValueError`等)将传播异常,但这是可以接受的,让用户尽早知道这些疯狂的类型在好的环境中是不可接受的;但是,能够求和为标量的"向量"(Python标准库中没有,但当然有许多第三方扩展中会有)在这里也会给出错误的结果,因此(例如)这个检查应该在"不允许可迭代"的检查之后进行(例如,检查`iter(x)`是否引发`TypeError`,或者检查特殊方法`__iter__`的存在--如果你在Python2.5或更早版本中,因此需要自己进行检查)。

对于这样复杂的情况,了解抽象基类可能会更有动力...;-)

但是在`numbers`模块中有一个`Number`的抽象基类。文档中称:"`numbers`模块(PEP 3141)定义了一个层次结构的数值抽象基类,逐步定义了更多的操作。"

0
0 Comments

这个问题的出现是因为在Python中判断一个对象是否为数字的方式有多种,而且有些方式可能会产生一些意想不到的结果。为了解决这个问题,可以使用Python中的numbers模块中的Number类来判断一个对象是否为数字,具体的做法是使用isinstance(n, Number)。下面是一个示例代码:

from numbers import Number
from decimal import Decimal
from fractions import Fraction
for n in [2, 2.0, Decimal('2.0'), complex(2, 0), Fraction(2, 1), '2']:
    print(f'{n!r:>14} {isinstance(n, Number)}')

运行结果如下:

              2 True
            2.0 True
 Decimal('2.0') True
         (2+0j) True
 Fraction(2, 1) True
            '2' False

这种方法可以判断一个对象是否为数字,但它与鸭子类型的思想相悖。如果你更关心一个对象的行为而不是它的类型,可以假设对象是一个数字,并使用异常来判断它是否不是一个数字。

另外,上面给出的方法会认为True是一个数字,这可能不是你想要的结果。如果要排除布尔值(例如验证操作),可以使用以下代码:

isinstance(value, Number) and type(value) != bool

此外,上面的方法会将float("-inf")认为是一个数字,这在某些情况下可能不合适。所以根据具体情况,可能需要进行一些额外的判断。

0