问题:检查对象是否为数字的最有效方法是什么?

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

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

检查,如果事情是intfloatlongbool很烦人,不包括可能像数字用户定义的对象。但是,__mul__例如,检查并不够好,因为我刚刚描述的向量类将定义__mul__,但它不是我想要的那种类型。

Given an arbitrary python object, what’s the best way to determine whether it is a number? Here is is defined as acts like a number in certain circumstances.

For example, say you are writing a vector class. If given another vector, you want to find the dot product. If given a scalar, you want to scale the whole vector.

Checking if something is int, float, long, bool is annoying and doesn’t cover user-defined objects that might act like numbers. But, checking for __mul__, for example, isn’t good enough because the vector class I just described would define __mul__, but it wouldn’t be the kind of number I want.


回答 0

使用模块测试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

当然,这与鸭子的打字相反。如果你更关心的对象如何行为,而不是它什么,执行您的操作,如果你有一个号码,使用异常,否则告诉你。

Use from the module to test isinstance(n, Number) (available since 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

This is, of course, contrary to duck typing. If you are more concerned about how an object acts rather than what it is, perform your operations as if you have a number and use exceptions to tell you otherwise.


回答 1

您要检查是否有物体

在某些情况下像数字一样

如果您使用的是Python 2.5或更早版本,则唯一的真实方法是检查某些“特定情况”并查看。

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

0在某些情况下,Bach达到2.5或更早版本时,“可以添加但不能迭代”可能是一个很好的定义。但是,您确实需要问自己,您要问的是,您要考虑的“数字”一定一定能够做的,而它绝对不能做的是什么,然后检查。

在2.6或更高版本中也可能需要这样做,也许是出于进行自己的注册以添加您尚未注册的您所关心的类型的目的numbers.Numbers-如果您想排除某些声称其为数字的类型,但是您只是无法处理,这需要更多的注意,因为ABC没有unregister方法[[例如,您可以制作自己的ABC WeirdNum并在其中注册所有此类怪异类型,然后isinstance在继续进行之前先检查其保释金检查isinstance正常numbers.Number是否继续成功。

顺便说一句,是否以及何时需要检查是否x可以做某事,通常必须尝试以下操作:

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

__add__本身的存在告诉您没有什么用处,因为例如所有序列都具有将其与其他序列连接的目的。例如,此检查等效于定义“数字是某种东西,使得这样的事物的序列是内置函数的有效单个参数sum”。完全怪异的类型(例如,总和为0时引发“错误的”异常的类型,例如a ZeroDivisionErrorValueError&c)将传播异常,但这没关系,让用户尽快知道这样的疯狂类型根本不能接受公司;-); 但是,一个可乘以标量的“向量”(Python的标准库没有),但是在这里它当然是作为第三方扩展而流行的),在这里也会给出错误的结果,因此(例如“不允许迭代”(例如,检查是否iter(x)加注TypeError,或者是否存在特殊方法__iter__-如果您的年龄在2.5或更早,因此需要您自己进行检查)。

简要了解一下此类复杂性可能足以激励您在可行的情况下改为依赖抽象基类。

You want to check if some object

acts like a number in certain circumstances

If you’re using Python 2.5 or older, the only real way is to check some of those “certain circumstances” and see.

In 2.6 or better, you can use isinstance with numbers.Number — an abstract base class (ABC) that exists exactly for this purpose (lots more ABCs exist in the collections module for various forms of collections/containers, again starting with 2.6; and, also only in those releases, you can easily add your own abstract base classes if you need to).

Bach to 2.5 and earlier, “can be added to 0 and is not iterable” could be a good definition in some cases. But, you really need to ask yourself, what it is that you’re asking that what you want to consider “a number” must definitely be able to do, and what it must absolutely be unable to do — and check.

This may also be needed in 2.6 or later, perhaps for the purpose of making your own registrations to add types you care about that haven’t already be registered onto numbers.Numbers — if you want to exclude some types that claim they’re numbers but you just can’t handle, that takes even more care, as ABCs have no unregister method [[for example you could make your own ABC WeirdNum and register there all such weird-for-you types, then first check for isinstance thereof to bail out before you proceed to checking for isinstance of the normal numbers.Number to continue successfully.

BTW, if and when you need to check if x can or cannot do something, you generally have to try something like:

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

The presence of __add__ per se tells you nothing useful, since e.g all sequences have it for the purpose of concatenation with other sequences. This check is equivalent to the definition “a number is something such that a sequence of such things is a valid single argument to the builtin function sum“, for example. Totally weird types (e.g. ones that raise the “wrong” exception when summed to 0, such as, say, a ZeroDivisionError or ValueError &c) will propagate exception, but that’s OK, let the user know ASAP that such crazy types are just not acceptable in good company;-); but, a “vector” that’s summable to a scalar (Python’s standard library doesn’t have one, but of course they’re popular as third party extensions) would also give the wrong result here, so (e.g.) this check should come after the “not allowed to be iterable” one (e.g., check that iter(x) raises TypeError, or for the presence of special method __iter__ — if you’re in 2.5 or earlier and thus need your own checks).

A brief glimpse at such complications may be sufficient to motivate you to rely instead on abstract base classes whenever feasible…;-).


回答 2

这是一个exceptions真正发光的好例子。只需执行对数字类型的处理,然后TypeError从其他所有类型中捕获即可。

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

This is a good example where exceptions really shine. Just do what you would do with the numeric types and catch the TypeError from everything else.

But obviously, this only checks if a operation works, not whether it makes sense! The only real solution for that is to never mix types and always know exactly what typeclass your values belong to.


回答 3

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

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__为乘以零时返回零,但这是一个极端的exceptions。该解决方案应涵盖您生成/诱骗的所有正常代码和健全代码。

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

输出:

False == isNumber([0 1])

Multiply the object by zero. Any number times zero is zero. Any other result means that the object is not a number (including exceptions)

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

Using isNumber thusly will give the following output:

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

Output:

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)

There probably are some non-number objects in the world that define __mul__ to return zero when multiplied by zero but that is an extreme exception. This solution should cover all normal and sane code that you generate/encouter.

numpy.array example:

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

output:

False == isNumber([0 1])

回答 4

为了改写您的问题,您正在尝试确定某物是集合还是单个值。试图比较某物是矢量还是数字,就是将苹果与橘子进行比较-我可以使用字符串或数字的矢量,也可以使用单个字符串或数字。您对拥有的数量(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]

最终,测试某事物是否类似于矢量比测试某事物是否类似于标量要容易。如果您遇到不同类型的值(例如,字符串,数字等),那么程序的逻辑可能需要做些工作-您最终是如何尝试将字符串乘以数字向量的?

To rephrase your question, you are trying to determine whether something is a collection or a single value. Trying to compare whether something is a vector or a number is comparing apples to oranges – I can have a vector of strings or numbers, and I can have a single string or single number. You are interested in how many you have (1 or more), not what type you actually have.

my solution for this problem is to check whether the input is a single value or a collection by checking the presence of __len__. For example:

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]

Or, for the duck-typing approach, you can try iterating on foo first:

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]

Ultimately, it is easier to test whether something is vector-like than to test whether something is scalar-like. If you have values of different type (i.e. string, numeric, etc.) coming through, then the logic of your program may need some work – how did you end up trying to multiply a string by a numeric vector in the first place?


回答 5

总结/评估现有方法:

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

To summarize / evaluate existing methods:

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

(I came here by this question)

Code

#!/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))

回答 6

最好以相反的方式进行操作:检查它是否是向量。如果是,则进行点积运算,在所有其他情况下,将尝试进行标量乘法。

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

Probably it’s better to just do it the other way around: You check if it’s a vector. If it is, you do a dot product and in all other cases you attempt scalar multiplication.

Checking for the vector is easy, since it should of your vector class type (or inherited from it). You could also just try first to do a dot-product, and if that fails (= it wasn’t really a vector), then fall back to scalar multiplication.


回答 7

只是为了补充。也许我们可以如下结合使用isinstance和isdigit来确定值是否为数字(int,float等)

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

Just to add upon. Perhaps we can use a combination of isinstance and isdigit as follows to find whether a value is a number (int, float, etc)

if isinstance(num1, int) or isinstance(num1 , float) or num1.isdigit():


回答 8

对于假设的向量类:

假设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 )

For the hypothetical vector class:

Suppose v is a vector, and we are multiplying it by x. If it makes sense to multiply each component of v by x, we probably meant that, so try that first. If not, maybe we can dot? Otherwise it’s a type error.

EDIT — the below code doesn’t work, because 2*[0]==[0,0] instead of raising a TypeError. I leave it because it was commented-upon.

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

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

float(x)

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

I had a similar issue, when implementing a sort of vector class. One way to check for a number is to just convert to one, i.e. by using

float(x)

This should reject cases where x cannot be converted to a number; but may also reject other kinds of number-like structures that could be valid, for example complex numbers.


回答 10

如果要根据参数类型调用不同的方法,请查看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)因为我们仍在定义type Vector,因此尚未定义类型名称。相反,我使用的是基类型list,它甚至允许您找到a Vector和a 的点积list

If you want to call different methods depending on the argument type(s), look into multipledispatch.

For example, say you are writing a vector class. If given another vector, you want to find the dot product. If given a scalar, you want to scale the whole vector.

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]

Unfortunately, (to my knowledge) we can’t write @dispatch(Vector) since we are still defining the type Vector, so that type name is not yet defined. Instead, I’m using the base type list, which allows you to even find the dot product of a Vector and a list.


回答 11

简短的方法:

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

输出:

True

如果对象是字符串,则将返回’False’:

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

输出:

False

Short and simple way :

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

Output :

True

If the object is a string, ‘False’ will be returned :

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

Output :

False

回答 12

您有一个数据项,说rec_day当写入文件时将是一个float。但程序处理期间,可以是floatintstr类型(str初始化一个新的记录时被使用并且包含一个伪标记的值)。

然后,您可以检查一下是否有此号码

                type(rec_day) != str 

我已经以这种方式构造了一个python程序,然后将其作为数字检查放入“维护补丁”中。这是Python方式吗?很可能没有,因为我以前使用COBOL编程。

You have a data item, say rec_day that when written to a file will be a float. But during program processing it can be either float, int or str type (the str is used when initializing a new record and contains a dummy flag value).

You can then check to see if you have a number with this

                type(rec_day) != str 

I’ve structured a python program this way and just put in ‘maintenance patch’ using this as a numeric check. Is it the Pythonic way? Most likely not since I used to program in COBOL.


回答 13

您可以使用isdigit()函数。

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

You could use the isdigit() function.

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

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。