给定一个任意的python对象,确定它是否是数字的最佳方法是什么?此处is
定义为acts like a number in certain circumstances
。
例如,假设您正在编写矢量类。如果给出另一个向量,您想要找到点积。如果给定标量,则需要缩放整个向量。
检查某些内容是int
,float
,long
,bool
是否令人讨厌,并且不包含可能与数字相同的用户定义对象。但是,例如,检查__mul__
是不够好的,因为我刚才描述的矢量类会定义__mul__
,但它不会是我想要的那种数字。
答案 0 :(得分:114)
使用Number
模块中的numbers
来测试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
这当然与鸭子打字相反。如果您更关心对象的行为方式而不是 ,请执行您的操作,就好像您有一个数字并使用异常来告诉您。
答案 1 :(得分:29)
您想要检查是否有某个对象
在某些情况下就像一个数字 情况
如果您使用的是Python 2.5或更早版本,唯一真正的方法是检查其中某些“特定情况”并查看。
在2.6或更高版本中,您可以将isinstance
与numbers.Number一起使用 - 一个完全为此目的而存在的抽象基类(ABC)(collections
模块中存在更多ABCs对于各种形式的集合/容器,再次从2.6开始;并且,只有在那些版本中,您可以根据需要轻松添加自己的抽象基类。
巴赫到2.5及更早,
“可以添加到0
并且不可迭代”在某些情况下可能是一个很好的定义。但,
你真的需要问问自己,你问的是什么你想要考虑的“数字”必须绝对能够做,它必须绝对是无法< / strong>要做 - 并检查。
在2.6或更高版本中也可能需要这样做,也许是为了让您自己的注册添加您尚未注册的类型numbers.Numbers
- 如果您想排除一些声称它们是数字但你无法处理的类型,这需要更加小心,因为ABC没有unregister
方法[[例如你可以制作自己的ABC] {{1并注册所有这些奇怪的类型,然后在继续检查正常WeirdNum
的{{1}}以继续成功之前,首先检查其isinstance
以进行纾困。
isinstance
是否可以做某事,您通常需要尝试以下方式:
numbers.Number
x
本身的存在告诉你没什么用处,因为例如所有序列都有它以便与其他序列连接。例如,此检查等同于“数字就是这样的事物的序列是内置函数try: 0 + x
except TypeError: canadd=False
else: canadd=True
的有效单个参数”。完全奇怪的类型(例如,当总和为0时引发“错误”异常的类型,例如,__add__
或sum
&amp; c)将传播异常,但是没关系,让用户尽快知道这种疯狂的类型在好公司中是不可接受的;-);但是,一个可以与标量相加的“向量”(Python的标准库没有一个,但当然它们作为第三方扩展很受欢迎)也会在这里给出错误的结果,所以(例如)这个检查应该来了< em>在之后“不允许迭代”(例如,检查ZeroDivisionError
是否会引发ValueError
,还是存在特殊方法iter(x)
- 如果你'重新在2.5或更早,因此需要你自己的检查。)
对这些并发症的简要介绍可能足以激励您在可行时依赖抽象基类......; - )。
答案 2 :(得分:16)
这是一个很好的例子,异常真正闪耀。只需按照数字类型执行操作,然后从其他所有内容中捕获TypeError
。
但显然,这只会检查操作是否有效,而不是是否有意义!唯一真正的解决方案是永远不要混合类型,并且始终确切地知道您的值所属的类型类。
答案 3 :(得分:4)
将对象乘以零。任何数字零都为零。任何其他结果意味着该对象不是数字(包括例外)
def isNumber(x):
try:
return 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__
在乘以零时返回零,但这是一个极端的例外。此解决方案应涵盖您生成/加密的所有普通和理智代码。
答案 4 :(得分:3)
要重新解释您的问题,您正在尝试确定某些内容是集合还是单个值。试图比较某些东西是矢量还是数字是比较苹果和橙子 - 我可以有一个字符串或数字的向量,我可以有一个字符串或单个数字。 您感兴趣的是您拥有的数量(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]
或者,对于鸭子分类方法,您可以先尝试迭代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]
最终,测试某些东西是否像矢量一样比测试某些东西是否是标量更容易。如果您有不同类型的值(即字符串,数字等),那么程序的逻辑可能需要一些工作 - 您最初是如何尝试将字符串乘以数字向量的? / p>
答案 5 :(得分:2)
可能反过来做的更好:你检查它是否是一个向量。如果是,则执行点积,在所有其他情况下,您尝试标量乘法。
检查向量很简单,因为它应该是矢量类类型(或从它继承)。你也可以先尝试做一个点积,如果失败了(=它实际上不是矢量),那么就回到标量乘法。
答案 6 :(得分:2)
总结/评估现有方法:
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
(我来自this question)
#!/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))
答案 7 :(得分:1)
只是补充一下。 也许我们可以使用isinstance和isdigit的组合来查找值是否为数字(int,float等)
如果是isinstance(num1,int)或isinstance(num1,float)或num1.isdigit():
答案 8 :(得分:0)
对于假设的矢量类:
假设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 )
答案 9 :(得分:0)
在实现某种矢量类时,我遇到了类似的问题。检查数字的一种方法是只转换为1,即使用
float(x)
这应该拒绝x无法转换为数字的情况;但也可能拒绝其他可能有效的类似数字的结构,例如复数。
答案 10 :(得分:0)
如果要根据参数类型调用不同的方法,请查看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
,它甚至允许您找到Vector
和list
的点积。
答案 11 :(得分:0)
简单快捷的方法:
obj = 12345
print(isinstance(obj,int))
输出:
True
如果对象是字符串,则将返回'False':
obj = 'some string'
print(isinstance(obj,int))
输出:
False
答案 12 :(得分:0)
您有一个数据项,说rec_day
,当写入文件时将是float
。但是在程序处理期间,它可以是float
,int
或str
类型(初始化新记录时使用str
,并包含一个虚拟标志值)。>
然后您可以检查一下是否有这个号码
type(rec_day) != str
我已经用这种方式构造了一个python程序,并且只是使用它作为数字检查放入了“维护补丁”。这是Python方式吗?因为我以前使用COBOL编程,所以很可能没有。
答案 13 :(得分:0)
可以在一个简单的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
答案 14 :(得分:-1)
您可以使用isdigit()函数。
>>> x = "01234"
>>> a.isdigit()
True
>>> y = "1234abcd"
>>> y.isdigit()
False