要求:
以下是我使用此代码的部分代码。
def make_operand(symbol, left=None, right=None):
valid_symbols = ['*', '/', '+', '-']
if symbol in valid_symbols:
return Operand(symbol, left, right)
as_int = re.compile("^-?[0-9]+$").match(str(symbol))
as_float = re.compile("^[-+]?[0-9]*\.?[0-9]+$").match(str(symbol))
as_number = int(symbol) if as_int else float(symbol) if as_float else None
if as_number:
return NumericOperand(as_number)
raise ValueError("Invalid symbol or number")
这样可行,但看起来很乱,闻起来有点不对劲。
使用try块的实现也有效,但似乎不那么简单:
as_number = None
try:
as_float = float(symbol)
except ValueError:
as_float = None
if as_float:
as_int = int(as_float)
as_number = as_int if as_int == as_float else as_float
if as_number:
return NumericOperand(as_number)
raise ValueError("Invalid symbol or number")
是否有更好的方法,或者其中一种接近Pythonic的做法?
答案 0 :(得分:2)
如果您不介意第三方模块,那么有一个名为fastnumbers的C-exension模块就是为此目的而设计的。 fast_real函数完全符合您的要求(假设您使用coerce=True
上提供的fastnumbers>=0.7.4
)。
完全披露,我是作者。
>>> from fastnumbers import fast_real
>>> fast_real('56')
56
>>> fast_real('56.0')
56
>>> fast_real('56.07')
56.07
>>> fast_real('56.07 lb')
'56.07 lb'
>>> fast_real(56.07)
56.07
>>> fast_real(56.0)
56.0
>>> fast_real(56.0, coerce=True)
56
>>> fast_real(56)
56
>>> fast_real('56.07 lb', raise_on_invalid=True)
Traceback (most recent call last):
...
ValueError: could not convert string to float: '56.07 lb'
答案 1 :(得分:0)
因为PEP 367任何可以转换为整数而没有精度损失的python对象将定义__index__
方法,以便可以在索引中使用它。唯一的特例是使用str
,您可以这样做:
def as_num(value):
if isinstance(value,str):
try:
return int(value)
except ValueError:
pass #don't put return float(value) here or you will get chained exceptions
return float(value) #this might fail and raise the error
elif hasattr(value,"__index__"):
return value.__index__() #possibly just int(value) if the method exists?
else:
return float(value) #this would fail if the object cannot be cast to a float
虽然有可能在未定义__index__
但int
和float
返回等效值的特殊情况下仍然无法接受,在这种情况下,您已拥有的代码是几乎没事。只需将if as_float
更改为if as_float is not None
,这样symbol=0
就不会失败而且你很高兴,虽然结构可以简化一点:
try:
as_float = float(symbol)
except ValueError:
raise ValueError("Invalid symbol or number") #maybe just let the other error go instead?
else:
if as_float.is_integer():
return NumericOperand(int(as_float))
return NumericOperand(as_float)