<p>你知道,我发现(而且我已经反复测试过)无论出于什么原因,try/except都没有那么好的表现。我经常尝试几种方法来做事情,我认为我从来没有找到过一种方法使用try/except来执行测试中最好的方法,事实上,在我看来,这些方法通常已经接近最坏的,如果不是最坏的。不是每一种情况,但在许多情况下。我知道很多人都说这是“Python式”的方式,但这是我和他们分道扬镳的一个方面。对我来说,它既不是很好的表现,也不是很优雅,所以,我倾向于只用于错误捕获和报告。</p>
<p>我要抱怨的是PHP、perl、ruby、C,甚至是畸形的shell都有简单的函数来测试整型hood的字符串,但是在验证这些假设时的尽职调查让我大吃一惊!显然这种缺乏是一种常见病。</p>
<p>以下是布鲁诺邮报的一个快速而肮脏的编辑:</p>
<pre><code>import sys, time, re
g_intRegex = re.compile(r"^([+-]?[1-9]\d*|0)$")
testvals = [
# integers
0, 1, -1, 1.0, -1.0,
'0', '0.','0.0', '1', '-1', '+1', '1.0', '-1.0', '+1.0', '06',
# non-integers
'abc 123',
1.1, -1.1, '1.1', '-1.1', '+1.1',
'1.1.1', '1.1.0', '1.0.1', '1.0.0',
'1.0.', '1..0', '1..',
'0.0.', '0..0', '0..',
'one', object(), (1,2,3), [1,2,3], {'one':'two'},
# with spaces
' 0 ', ' 0.', ' .0','.01 '
]
def isInt_try(v):
try: i = int(v)
except: return False
return True
def isInt_str(v):
v = str(v).strip()
return v=='0' or (v if v.find('..') > -1 else v.lstrip('-+').rstrip('0').rstrip('.')).isdigit()
def isInt_re(v):
import re
if not hasattr(isInt_re, 'intRegex'):
isInt_re.intRegex = re.compile(r"^([+-]?[1-9]\d*|0)$")
return isInt_re.intRegex.match(str(v).strip()) is not None
def isInt_re2(v):
return g_intRegex.match(str(v).strip()) is not None
def check_int(s):
s = str(s)
if s[0] in ('-', '+'):
return s[1:].isdigit()
return s.isdigit()
def timeFunc(func, times):
t1 = time.time()
for n in range(times):
for v in testvals:
r = func(v)
t2 = time.time()
return t2 - t1
def testFuncs(funcs):
for func in funcs:
sys.stdout.write( "\t%s\t|" % func.__name__)
print()
for v in testvals:
if type(v) == type(''):
sys.stdout.write("'%s'" % v)
else:
sys.stdout.write("%s" % str(v))
for func in funcs:
sys.stdout.write( "\t\t%s\t|" % func(v))
sys.stdout.write("\r\n")
if __name__ == '__main__':
print()
print("tests..")
testFuncs((isInt_try, isInt_str, isInt_re, isInt_re2, check_int))
print()
print("timings..")
print("isInt_try: %6.4f" % timeFunc(isInt_try, 10000))
print("isInt_str: %6.4f" % timeFunc(isInt_str, 10000))
print("isInt_re: %6.4f" % timeFunc(isInt_re, 10000))
print("isInt_re2: %6.4f" % timeFunc(isInt_re2, 10000))
print("check_int: %6.4f" % timeFunc(check_int, 10000))
</code></pre>
<p>以下是性能比较结果:</p>
<pre><code>timings..
isInt_try: 0.6426
isInt_str: 0.7382
isInt_re: 1.1156
isInt_re2: 0.5344
check_int: 0.3452
</code></pre>
<p>C方法可以扫描一次,然后就可以完成了。我认为,C方法扫描字符串一次是正确的做法。</p>
<p>编辑:</p>
<p>我已经更新了上面的代码,使之能够在Python3.5中工作,并且包含了来自当前最有投票权的答案的check_int函数,并且使用了当前最流行的regex,我可以找到它来测试整型hood。这个正则表达式拒绝像“abc 123”这样的字符串。我加了‘abc 123’作为测试值。</p>
<p>在这一点上,我非常感兴趣地注意到,没有一个被测试的函数,包括try方法、流行的check_int函数和最流行的用于测试整数hood的regex,返回所有测试值的正确答案(好吧,这取决于您认为正确答案是什么;请参见下面的测试结果)。</p>
<p>函数的作用是:自动截断浮点数的小数部分,并返回小数之前的整数部分,除非浮点数首先转换为字符串。</p>
<p>check_int()函数为0和1等值返回false(技术上是整数),为06等值返回true。</p>
<p>以下是当前(Python3.5)测试结果:</p>
<pre><code> isInt_try | isInt_str | isInt_re | isInt_re2 | check_int |
0 True | True | True | True | True |
1 True | True | True | True | True |
-1 True | True | True | True | True |
1.0 True | True | False | False | False |
-1.0 True | True | False | False | False |
'0' True | True | True | True | True |
'0.' False | True | False | False | False |
'0.0' False | True | False | False | False |
'1' True | True | True | True | True |
'-1' True | True | True | True | True |
'+1' True | True | True | True | True |
'1.0' False | True | False | False | False |
'-1.0' False | True | False | False | False |
'+1.0' False | True | False | False | False |
'06' True | True | False | False | True |
'abc 123' False | False | False | False | False |
1.1 True | False | False | False | False |
-1.1 True | False | False | False | False |
'1.1' False | False | False | False | False |
'-1.1' False | False | False | False | False |
'+1.1' False | False | False | False | False |
'1.1.1' False | False | False | False | False |
'1.1.0' False | False | False | False | False |
'1.0.1' False | False | False | False | False |
'1.0.0' False | False | False | False | False |
'1.0.' False | False | False | False | False |
'1..0' False | False | False | False | False |
'1..' False | False | False | False | False |
'0.0.' False | False | False | False | False |
'0..0' False | False | False | False | False |
'0..' False | False | False | False | False |
'one' False | False | False | False | False |
<obj..> False | False | False | False | False |
(1, 2, 3) False | False | False | False | False |
[1, 2, 3] False | False | False | False | False |
{'one': 'two'} False | False | False | False | False |
' 0 ' True | True | True | True | False |
' 0.' False | True | False | False | False |
' .0' False | False | False | False | False |
'.01 ' False | False | False | False | False |
</code></pre>
<p>刚才我试着添加这个函数:</p>
<pre><code>def isInt_float(s):
try:
return float(str(s)).is_integer()
except:
return False
</code></pre>
<p>它的性能几乎和check_int(0.3486)一样好,对于1.0和0.0以及+1.0和0这样的值,它返回true。0等等。但它也会返回“06”的真值,所以。我想是你选了毒药吧。</p>