检查对象是否为数字的最pythonic方法是什么?

Cla*_*diu 104 python types numbers

给定一个任意python对象,确定它是否是数字的最佳方法是什么?这里is定义为acts like a number in certain circumstances.

例如,假设您正在编写矢量类.如果给出另一个向量,您想要找到点积.如果给定标量,则需要缩放整个向量.

检查,如果事情是int,float,long,bool很烦人,不包括可能像数字用户定义的对象.但是,__mul__例如,检查是不够好的,因为我刚才描述的矢量类会定义__mul__,但它不是我想要的那种数字.

Ste*_*ski 125

使用Numbernumbers模块测试isinstance(n, Number)(因为2.6可用).

>>> 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 '%15s %s' % (n.__repr__(), isinstance(n, Number))
              2 True
            2.0 True
 Decimal('2.0') True
         (2+0j) True
 Fraction(2, 1) True
            '2' False
Run Code Online (Sandbox Code Playgroud)

当然,这与鸭子打字相反.如果您更关心对象的行为而不是它的作用,请执行操作,就好像您有一个数字并使用异常来告诉您.

  • 只是要注意numpy不足以使用类号,一些numpy数字类型将返回**False**`isinstance(numpy.uint8(1),numbers.Number)` (6认同)
  • 关于鸭子打字的好评. (3认同)
  • 这个答案会说 True 是一个数字......这可能并不总是你想要的。对于排除布尔值(想想验证 fe),我会说 `isinstance(value, Number) 和 type(value) != bool` (3认同)
  • 哦,所以Number类型类*确实存在! (2认同)
  • 当你将向量乘以X时,首选做聪明的东西,而不是鸭子的东西.在这种情况下,你想根据X _is_做不同的事情.(它可能会成倍增加,但结果可能是荒谬的.) (2认同)

Ale*_*lli 30

你想检查是否有一些对象

在某些情况下就像一个数字

如果您使用的是Python 2.5或更早版本,唯一真正的方法是检查其中某些"特定情况"并查看.

在2.6或更好的,你可以使用isinstancenumbers.Number -一个抽象基类(ABC)存在正是为了这个目的(其它更多的ABC中存在的collections模块为各种形式的集合/容器,重新开始与2.6;以及也只有在那些版本中,如果需要,您可以轻松添加自己的抽象基类.

0在某些情况下,Bach到2.5及更早,"可以添加并且不可迭代"可能是一个很好的定义.但是,你真的需要问问自己,你要问的是你想要考虑的"数字"肯定能做什么,以及它必须绝对无法做什么 - 并检查.

在2.6或更高版本中也可能需要这样做,也许是为了让您自己的注册添加您尚未注册的类型numbers.Numbers- 如果您想要排除某些声称它们是数字但您的类型只是无法处理,这需要更加小心,因为基本知识有没有unregister方法[例如,你可以使自己的ABC WeirdNum,并在那里注册所有这些怪异适合你的类型,则首先检查isinstance其保释出来,然后再继续检查isinstance正常numbers.Number继续成功.

顺便说一句,如果您需要检查是否x可以做某事,您通常必须尝试以下方法:

try: 0 + x
except TypeError: canadd=False
else: canadd=True
Run Code Online (Sandbox Code Playgroud)

__add__本身的存在告诉你没什么用处,因为例如所有序列都有它用于与其他序列连接的目的.例如,该检查等同于"数字就是这样的事物的序列是内置函数的有效单个参数sum"的定义.完全奇怪的类型(例如,当总和为0时引发"错误"异常的类型,例如a ZeroDivisionError或者ValueErrorc)会传播异常,但是没关系,让用户尽快知道这样的疯狂类型是不可接受的公司;-); 但是,一个可以与标量相加的"向量"(Python的标准库没有一个,但当然它们作为第三方扩展很受欢迎)也会在这里给出错误的结果,所以(例如"不允许可迭代的"(例如,检查iter(x)加注TypeError,或者是否存在特殊方法__iter__- 如果您是2.5或更早,因此需要您自己的检查).

对这些复杂情况的简要介绍可能足以激励您在可行时依赖抽象基类...... ;-).


Joc*_*zel 17

这是异常真正闪耀的一个很好的例子.只需按照数字类型执行操作,然后TypeError从其他所有内容中捕获.

但显然,这只会检查一个操作是否有效,而不是它是否有意义!唯一真正的解决方案是永远不要混合类型,并且始终确切地知道您的值所属的类型类.

  • 这是传统的方法,但ABCs已经被很好地引入,以便从纯鸭子打字中取走*并且转移到一个世界,其中`isinstance`在很多情况下实际上可以_useful_(=="检查它是否有意义"以及正式的运营适用性).对于长期使用Python的人来说,这是一个非常重要的转变,但是Python的哲学中一个非常重要的微妙趋势是忽略它是一个严重的错误. (12认同)
  • 没有什么反对鸭子打字。这就是我会做的。但数字有一个抽象基类:numbers.Number。 (2认同)

shr*_*use 5

将对象乘以零。任何数字乘以零都是零。任何其他结果表示对象不是数字(包括异常)

def isNumber(x):
    try:
        return bool(0 == x*0)
    except:
        return False
Run Code Online (Sandbox Code Playgroud)

因此使用 isNumber 将给出以下输出:

class A: pass 

def foo(): return 1

for x in [1,1.4, A(), range(10), foo, foo()]:
    answer = isNumber(x)
    print('{answer} == isNumber({x})'.format(**locals()))
Run Code Online (Sandbox Code Playgroud)

输出:

True == isNumber(1)
True == isNumber(1.4)
False == isNumber(<__main__.A instance at 0x7ff52c15d878>)
False == isNumber([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
False == isNumber(<function foo at 0x7ff52c121488>)
True == isNumber(1)
Run Code Online (Sandbox Code Playgroud)

世界上可能有一些非数字对象定义__mul__在乘以零时返回零,但这是一个极端的例外。此解决方案应涵盖您生成/遇到的所有正常健全的代码。

numpy.array 示例:

import numpy as np

def isNumber(x):
    try:
        return bool(x*0 == 0)
    except:
        return False

x = np.array([0,1])

answer = isNumber(x)
print('{answer} == isNumber({x})'.format(**locals()))
Run Code Online (Sandbox Code Playgroud)

输出:

False == isNumber([0 1])
Run Code Online (Sandbox Code Playgroud)

  • `真 * 0 == 0` (7认同)
  • 您的函数会错误地表示布尔值是数字 (4认同)