如何检查值是否逻辑整数?

时间:2014-11-15 13:17:00

标签: python python-3.x integer

我有一些函数在做数学的东西,需要采用整数agrmuents。

我知道我可以通过使用条件int来强制使用isinstance(x, int) 或更严格的type(x) == int,但IMO不是pythonic 我认为我的Python代码不应仅仅因为它是2.0而拒绝float

检查值逻辑整数的最佳方法是什么?

通过逻辑整数我的意思是任何类型的值,它代表整数。

能够用于int之类的算术运算,但我不需要检查它,
因为我相信在Python 任何条件都会被愚弄。

例如,
True-22.0Decimal(2)Fraction(4, 2) 逻辑整数
'2'2.5不是。

目前我使用int(x) == x,但我不确定这是否是最佳解决方案 我知道我可以使用float(x).is_integer()。 我也看到x % 1 == 0

4 个答案:

答案 0 :(得分:1)

解决此问题的一种方法是使用元类来定义__instancecheck__的自定义实现,然后定义具有元类的具体类,并将isinstance与您的具体类一起使用。

这有拉动元类机械的缺点,这通常是无关紧要的。

但它有一个优点,即干净地封装你希望用于意味着什么属性"逻辑整数" 您的应用程序。

这里有一些代码来展示这种方法:

class Integral(type):
    def __instancecheck__(self, other):
        try:
            cond1 = int(other) == other
            cond2 = (other >= 1.0) or (other < 1.0)
            # ... plus whatever other properties you want to check
            return all([cond1, cond2,])
        except:
            return False

class IntLike:
    __metaclass__ = Integral

print isinstance(-1, IntLike)
print isinstance('1', IntLike)
print isinstance(27.2, IntLike)
print isinstance(27.0, IntLike)
print isinstance(fractions.Decimal(2), IntLike)
print isinstance(fractions.Fraction(4, 2), IntLike)

打印:

True
False
False
True
True
True

请注意,摆脱逻辑上整数的数学概念应该适用于您的程序的想法很重要。除非你带来一些校验机制,否则你不会得到它。例如,您提到了某些功能可用的属性,特别是sqrt - 但除非您实现自定义行为以检查复杂结果,否则这对于负整数不可用。

它将是特定于应用程序的。例如,其他人可能会选择此代码并对其进行修改,以便'1' 注册为IntLike,并且可能为了他们的应用,它将是正确的。< / p>

这就是我喜欢这里的元类方法的原因。它允许您明确表示您要施加的每个条件,并将它们存储在一个位置。然后使用常规的isinstance机制,可以很清楚地向读者编写您想要做的事情。

最后,请注意,没有给定条件总是完美的。例如,下面的课程可以用来“愚弄”。 int(x) == x诀窍:

class MyInt(object):
    def __init__(self, value):
        self.value = value

    def __int__(self):
        return int(self.value)

    def __add__(self, other):
        return self.value + other

    #... define all needed int operators

    def __eq__(self, other):
        if isinstance(other, float):
            raise TypeError('How dare you compare me to a float!')
        return self.value == other

    # ..etc

然后你会得到这样的行为:

In [90]: mi = MyInt(3)

In [91]: mi + 4
Out[91]: 7

In [92]: mi == 3
Out[92]: True

In [93]: int(mi) == mi
Out[93]: True

In [94]: mi == 3.0
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-93-827bea4a197f> in <module>()
----> 1 mi == 3.0

<ipython-input-89-66fec92fab7d> in __eq__(self, other)
     13     def __eq__(self, other):
     14         if isinstance(other, float):
---> 15             raise TypeError('How dare you compare me to a float!')
     16         return self.value == other
     17 

TypeError: How dare you compare me to a float!

以及isinstance(mi, IntLike)是否返回True将完全取决于您如何实施MyInt的比较运算符以及您在Integral中所做的任何额外检查&#39; s __instancecheck__

答案 1 :(得分:1)

通常会检查Integral ABC(抽象基类),但浮点值通常不会被视为整数,无论​​它们的值如何。如果您需要,请记下他们的is_integer属性:

(1324.34).is_integer()
#>>> False

(1324.00).is_integer()
#>>> True

然后代码就是:

from numbers import Integral

def is_sort_of_integer(value):
    if isinstance(value, Integral):
        return True

    try:
        return value.is_integer()

    except AttributeError:
        return False

如果您还想处理没有Decimal方法的Fractionsis_integer等,那么最佳选择可能就是:

from numbers import Number, Integral

def is_sort_of_integer(value):
    if isinstance(value, Integral):
        return True

    if isinstance(value, Number):
        try:
            return not value % 1
        except TypeError:
            return False

    return False

在这种情况下,Integral检查不应该,但最好保留它。

答案 2 :(得分:0)

在某些情况下,int(x) == xx.isinteger()&amp; x % 1 == 0可以按照我想要的方式处理。

示例:

>>> big_float = 9999999999999999.1

big_float足以忽略从中减去一些小数字(AFAIK,它被称为下溢):

>>> big_float -1 == big_float
True

然后

>>> def fib(n):
...     current, prev = 1, 0
...     while n > 0:
...         current, prev, n = current+prev, current, n-1
...     return prev
...
>>> fib(big_float) #unwanted infinite loop
  

在某些情况下,int(x) == xx.isinteger()&amp; x % 1 == 0可以按照我想要的方式处理。

>>> int(big_float) == big_float
True
>>> big_float.is_integer()
True
>>> big_float % 1 == 0
True

解决方案

我们可以使用与big_float相同的方式检查int(big_float)

>>> int(big_float) -1 == big_float -1
False

当然,这种方法也适用于更简单的案例,如:

>>> x = 2.1
>>> int(x) -1 == x -1
False

当然,你不必减去1,你可以使用你需要的任何数学运算。

请注意,此情况可能会引发异常:

>>> x = '2'
>>> int(x) -1 == x -1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'str' and 'int'

答案 3 :(得分:-2)

简单,尝试将其转换为整数。如果int()有效,那么它在逻辑上是一个整数,否则就不是。

try:
    int(thing)
    is_integer = True
except ValueError:
    is_integer = False

但是,通常情况下,不要像这样做,你只需要在你需要的代码中使用int(thing),如果它最终不是一个整数并且适当地处理那个案例,就抓住错误。 / p>