我有一些函数在做数学的东西,需要采用整数agrmuents。
我知道我可以通过使用条件int
来强制使用isinstance(x, int)
或更严格的type(x) == int
,但IMO不是pythonic
我认为我的Python代码不应仅仅因为它是2.0
而拒绝float
。
检查值逻辑整数的最佳方法是什么?
通过逻辑整数我的意思是任何类型的值,它代表整数。
应能够用于int
之类的算术运算,但我不需要检查它,
因为我相信在Python 任何条件都会被愚弄。
例如,
True
,-2
,2.0
,Decimal(2)
,Fraction(4, 2)
逻辑整数,
'2'
和2.5
不是。
目前我使用int(x) == x
,但我不确定这是否是最佳解决方案
我知道我可以使用float(x).is_integer()
。
我也看到x % 1 == 0
。
答案 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
方法的Fractions
,is_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) == x
,x.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) == x
,x.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>