检查一个对象是否是一个数字的最简单的方法是什么?

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

例如,假设您正在编写一个向量类。如果给定另一个向量,你想找到点积。如果给定一个标量,你想缩放整个向量。

检查某些对象是否是 intfloatlongbool是令人讨厌的,并且没有覆盖可能像数字一样作用的用户定义对象。但是,例如,检查 __mul__还不够好,因为我刚才描述的向量类将定义 __mul__,但它不是我想要的那种数字。

39541 次浏览

这是异常真正发光的一个很好的例子。只要像处理数字类型一样,从其他所有内容中捕获 TypeError即可。

但是很明显,这只检查一个操作是否是 工程,而不是它是否是 有道理!唯一真正的解决方案是永远不要混合类型,并且始终准确地知道您的值属于哪个类型类。

也许反过来做会更好: 你检查它是否是一个矢量。如果是,你做一个点乘,在其他情况下你尝试标量乘法。

检查向量很容易,因为它应该是您的向量类类型(或从它继承)。你也可以先尝试做一个点乘,如果失败了(= 它不是一个向量) ,然后回到标量乘法。

对于假设的向量类:

假设 v是一个向量,我们将它乘以 x。如果将 v的每个组成部分乘以 x是有意义的,那么我们可能就是这个意思,所以先试试这个。如果没有,也许我们可以不?否则就是一个类型错误。

编辑 ——下面的代码不起作用,因为 2*[0]==[0,0]代替了 TypeError。我离开是因为它被评论了。

def __mul__( self, x ):
try:
return [ comp * x for comp in self ]
except TypeError:
return [ x * y for x, y in itertools.zip_longest( self, x, fillvalue = 0 )

你想要检查一些对象

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

如果您正在使用 Python 2.5或更高版本,那么唯一真正的方法是检查一些“特定情况”并查看。

在2.6或更高版本中,您可以将 isinstance数字,数字一起使用—— 数字,数字是一个抽象基类(ABC) ,正是为此目的而存在的(对于各种形式的集合/容器,collections模块中存在更多的 ABC,同样从2.6开始; 而且,只有在那些版本中,如果需要,您可以轻松地添加自己的抽象基类)。

巴赫到2.5或更早, 在某些情况下,“可以添加到 0并且不可迭代”可能是一个很好的定义。但是, 你真的需要问问你自己,你问的是什么,你想要考虑的“ a”一定能够成为 ,它一定是 不能要做什么——并检查。

这也可能在2.6或更高版本中需要,也许是为了让你自己的注册添加你关心的类型,你还没有注册到 numbers.Numbers-如果你想要 排除一些类型,声称他们是数字,但你只是不能处理,这需要更多的注意,因为 ABC 没有 unregister方法[[例如,你可以制作自己的 ABC WeirdNum和注册所有这些怪异的类型,然后先检查 isinstance的跳出之前,你继续检查 isinstance的正常 numbers.Number继续成功。

顺便说一句,如果你需要检查 x是否可以做一些事情,你通常必须尝试这样的事情:

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

__add__的存在本身并没有告诉你什么有用的信息,因为例如,所有序列都有它,用于与其他序列连接。例如,这个检查等同于定义“ a number is something so that a order of such things is a validsingle reference to the builtin function sum”。完全奇怪的类型(例如当总和为0时引发“错误”异常的类型,例如 ZeroDivisionErrorValueError & c)会传播异常,但是没关系,让用户尽快知道这种疯狂的类型在好的公司是不可接受的; ——但是,一个可以和标量相加的“向量”(Python 的标准库没有标量,但是当然它们作为第三方扩展很流行)也会在这里给出错误的结果,所以(例如)这个检查应该来自 之后 the“不允许迭代”一个(例如,检查 iter(x)是否引发 TypeError,或者检查特殊方法 __iter__是否存在——如果您在2.5或更早的版本中,因此需要自己进行检查)。

在可行的情况下,对这种复杂性的简短了解可能足以促使您依赖于抽象基类... ... ; ——)。

使用 numbers模块中的 Number来测试 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(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

当然,这与 Duck 类型相反。如果您更关心的是对象 行为的方式而不是它的 ,那么就像有一个数字那样执行操作,并使用异常来告诉您其他方法。

顺便说一句。 也许我们可以像下面这样使用 isinstance 和 isdigital 的组合来查找一个值是否是一个数字(int、 float 等)

如果 isinstance (num1,int)或 isinstance (num1,float)或 num1.isdigital () :

在实现某种向量类时,我遇到了类似的问题。检查一个数字的一种方法是只转换为一个,即使用

float(x)

这将拒绝 x 不能转换为数字的情况; 但也可能拒绝其他类似数字的有效结构,例如复数。

为了重新表述您的问题,您试图确定某个值是集合还是单个值。尝试比较某个东西是向量还是数字是比较苹果和橙子-我可以有一个字符串或数字的向量,我可以有一个单一的字符串或单一的数字。你感兴趣的是你有多少(1个或更多),不是你实际拥有的类型。

我对这个问题的解决方案是通过检查 __len__的存在来检查输入是单个值还是集合。例如:

def do_mult(foo, a_vector):
if hasattr(foo, '__len__'):
return sum([a*b for a,b in zip(foo, a_vector)])
else:
return [foo*b for b in a_vector]

或者,对于 Duck 类型化方法,您可以尝试首先在 foo上迭代:

def do_mult(foo, a_vector):
try:
return sum([a*b for a,b in zip(foo, a_vector)])
except TypeError:
return [foo*b for b in a_vector]

最终,测试某些内容是否类似于向量比测试某些内容是否类似于标量要容易得多。如果你有不同类型的值(如字符串、数值等) ,那么你的程序的逻辑可能需要一些工作-你是如何最终试图乘以一个字符串的数值向量摆在首位?

将物体乘以零。任何数乘以零等于零。任何其他结果意味着对象不是数字(包括异常)

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

因此,使用 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()))

产出:

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)

世界上可能存在一些非数字对象,它们将 __mul__定义为当乘以零时返回零,但这是一个极端的例外。这个解决方案应该涵盖您生成/输出的所有 正常理智代码。

数组例子:

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()))

产出:

False == isNumber([0 1])

您可以使用 isdigital ()函数。

>>> x = "01234"
>>> a.isdigit()
True
>>> y = "1234abcd"
>>> y.isdigit()
False

总结/评价现有方法:

Candidate    | type                      | delnan | mat | shrewmouse | ant6n
-------------------------------------------------------------------------
0            | <type 'int'>              |      1 |   1 |          1 |     1
0.0          | <type 'float'>            |      1 |   1 |          1 |     1
0j           | <type 'complex'>          |      1 |   1 |          1 |     0
Decimal('0') | <class 'decimal.Decimal'> |      1 |   0 |          1 |     1
True         | <type 'bool'>             |      1 |   1 |          1 |     1
False        | <type 'bool'>             |      1 |   1 |          1 |     1
''           | <type 'str'>              |      0 |   0 |          0 |     0
None         | <type 'NoneType'>         |      0 |   0 |          0 |     0
'0'          | <type 'str'>              |      0 |   0 |          0 |     1
'1'          | <type 'str'>              |      0 |   0 |          0 |     1
[]           | <type 'list'>             |      0 |   0 |          0 |     0
[1]          | <type 'list'>             |      0 |   0 |          0 |     0
[1, 2]       | <type 'list'>             |      0 |   0 |          0 |     0
(1,)         | <type 'tuple'>            |      0 |   0 |          0 |     0
(1, 2)       | <type 'tuple'>            |      0 |   0 |          0 |     0

(我是通过 这个问题来到这里的)

密码

#!/usr/bin/env python


"""Check if a variable is a number."""


import decimal




def delnan_is_number(candidate):
import numbers
return isinstance(candidate, numbers.Number)




def mat_is_number(candidate):
return isinstance(candidate, (int, long, float, complex))




def shrewmouse_is_number(candidate):
try:
return 0 == candidate * 0
except:
return False




def ant6n_is_number(candidate):
try:
float(candidate)
return True
except:
return False


# Test
candidates = (0, 0.0, 0j, decimal.Decimal(0),
True, False, '', None, '0', '1', [], [1], [1, 2], (1, ), (1, 2))


methods = [delnan_is_number, mat_is_number, shrewmouse_is_number, ant6n_is_number]


print("Candidate    | type                      | delnan | mat | shrewmouse | ant6n")
print("-------------------------------------------------------------------------")
for candidate in candidates:
results = [m(candidate) for m in methods]
print("{:<12} | {:<25} | {:>6} | {:>3} | {:>10} | {:>5}"
.format(repr(candidate), type(candidate), *results))

如果希望根据参数类型调用不同的方法,请查看 multipledispatch

例如,假设您正在编写一个向量类。如果给定另一个向量,你想找到点积。如果给定一个标量,你想缩放整个向量。

from multipledispatch import dispatch


class Vector(list):


@dispatch(object)
def __mul__(self, scalar):
return Vector( x*scalar for x in self)


@dispatch(list)
def __mul__(self, other):
return sum(x*y for x,y in zip(self, other))




>>> Vector([1,2,3]) * Vector([2,4,5])   # Vector time Vector is dot product
25
>>> Vector([1,2,3]) * 2                 # Vector times scalar is scaling
[2, 4, 6]

不幸的是,(据我所知)我们不能编写 @dispatch(Vector),因为我们仍然在定义类型 Vector,所以类型名称还没有定义。相反,我使用的是基本类型 list,它甚至允许您查找 Vectorlist的点乘。

简单明了的方法:

obj = 12345
print(isinstance(obj,int))

产出:

True

如果对象是字符串,则返回“ False”:

obj = 'some string'
print(isinstance(obj,int))

产出:

False

您有一个数据项,比如说 rec_day,当写入一个文件时,它将是一个 float。但是在程序处理过程中,它可以是 floatintstr类型(在初始化新记录时使用 str并包含一个虚拟标志值)。

然后您可以查看是否有这样的号码

                type(rec_day) != str

我以这种方式构建了一个 python 程序,并将其作为一个数字检查输入“维护补丁”。是蟒蛇的方式吗?很可能不会,因为我过去常常用 COBOL 编程。

可以在一个简单的 try 异常块中实现

def check_if_number(str1):
try:
int(float(str1))
return 'number'
except:
return 'not a number'


a = check_if_number('32322')
print (a)
# number

您可以使用 数字,数字来检查一个对象是否是一个数字。

对于数字,巨蟒3支持3种类型的 一个 href = “ https://docs.python.org/3/library/function tions.html # int”rel = “ nofollow noReferrer”> int ,一个 href = “ https://docs.python.org/3/library/function tions.html # plex”rel = “ nofollow noReferrer”> plex type,因此如果用 数字,数字检查3种类型的值,如下所示:

import numbers


print(type(100), isinstance(100, numbers.Number))
print(type(100.23), isinstance(100.23, numbers.Number))
print(type(100 + 2j), isinstance(100 + 2j, numbers.Number))

所有返回 True如下所示:

<class 'int'> True
<class 'float'> True
<class 'complex'> True

对于数字,巨蟒2支持4种类型的 一个 href = “ https://docs.python.org/2.7/library/function tions.html # int”rel = “ nofollow noReferrer”> int ,一个 href = “ https://docs.python.org/2.7/library/function tions.html # long”rel = “ nofollow noReferrer”> long ,一个 href = “ https://docs.python.org/2.7/library/function tions.html # plex”rel = “ nofollow noReferrer”> plex 类型,因此如果用 数字,数字检查4种类型的值,如下所示:

import numbers


print(type(100), isinstance(100, numbers.Number))
print(type(10000000000000000000), isinstance(10000000000000000000, numbers.Number))
print(type(100.23), isinstance(100.23, numbers.Number))
print(type(100 + 2j), isinstance(100 + 2j, numbers.Number))

所有返回 True如下所示:

(<type 'int'>, True)
(<type 'long'>, True)
(<type 'float'>, True)
(<type 'complex'>, True)