2010-06-05 71 views
1

我想使用Python 2.6和更高版本将字符串转换为浮动,但没有静默地将诸如'NaN''Inf'之类的东西转换为浮动对象。我希望它们被默默地忽略,就像任何无效的浮动表示形式的文本一样。转换字符串浮动没有沉默NaN/Inf转换

在2.6之前,float("NaN")会在Windows上引发ValueError。现在它返回一个float,math.isnan()返回True,这对我的应用程序来说不是有用的行为。 (正如指出的那样,这一直是一个平台相关的行为,但认为这是我的目的,不管它发生的不良行为。)

下面是我在此刻得到了:

import math 
def get_floats(source): 
    for text in source.split(): 
     try: 
      val = float(text) 
      if math.isnan(val) or math.isinf(val): 
       raise ValueError 
      yield val 
     except ValueError: 
      pass 

这是一个生成器,我可以提供包含代表实数的空白分隔序列的字符串。我希望它只产生那些纯粹是浮点数字表示的字段,如“1.23”或“-34e6”,但不是例如“NaN”或“-Inf”。根本不漂浮的东西,例如“你好”,也应该被忽略。

测试用例:

assert list(get_floats('1.23 foo -34e6 NaN -Inf')) == [1.23, -34000000.0] 

请建议你考虑更优雅的选择,即使他们涉及“三思而后行”(这通常被认为是在Python较小的做法)。

编辑澄清非浮动文本,如“你好”,也应该安静地被忽略。目的是只提取那些真正的数字而忽略其他的东西。

+0

鸡蛋里挑骨头:预2.6行为是完全依赖于平台。例如,在OS X上使用Python 2.5,float(“NaN”)返回一个nan。 – 2010-06-05 18:20:50

+0

马克,好点;我忘了那个。正如你可能知道的那样,在Windows平台上。 – 2010-06-06 12:34:45

回答

2

我我会这样写。我认为它结合简洁性和可读性。

def is_finite(x): 
    return not math.isnan(x) and not math.isinf(x) 

def get_floats(source): 
    for x in source.split(): 
     try: 
      yield float(x) 
     except ValueError: 
      pass 

def get_finite_floats(source): 
    return (x for x in get_floats(source) if is_finite(x)) 
+0

我没有在我的测试用例中包含一个例子,但我希望这样可以安静地忽略任何定义的浮动事物,例如简单的文本字符串,例如“富”。我会在问题中澄清。 – 2010-06-06 12:35:45

+0

我更改了代码以满足不断变化的要求。 – 2010-06-06 13:16:02

1

这是一个非常小的建议,但continue是不是引发一个异常快一点:

def get_floats(source): 
    for text in source.split(): 
     try: 
      val = float(text) 
      if math.isnan(val) or math.isinf(val): continue 
      yield val 
     except ValueError: 
      pass 

使用raise ValueError

% python -mtimeit -s'import test' "list(test.get_floats('1.23 -34e6 NaN -Inf Hello'))" 
10000 loops, best of 3: 22.3 usec per loop 

使用continue

% python -mtimeit -s'import test' "list(test.get_floats_continue('1.23 -34e6 NaN -Inf Hello'))" 
100000 loops, best of 3: 17.2 usec per loop 
+0

好点。在我原来的代码中,它不是在循环中,所以继续不会起作用,但这是一个很好的建议。 – 2010-06-06 12:36:20

+0

这并不公平 - 你在第二次测试中的循环次数是第一次测试的10倍。 – Puppy 2010-06-06 12:43:30

+1

@DeadMG:第一次执行命令10000次(然后重复测试3次),第二次执行命令100000次(然后重复执行3次)是正确的。但每个循环的usec指的是时间*除以循环次数*,所以这些数字是可比的。 – unutbu 2010-06-06 13:18:29

0

我投了保汉金的回答是为了便于阅读,但如果我不希望分裂代码尽可能多的,这里是我原来的一个变化那是不太笨重。

def get_only_numbers(source): 
    '''yield all space-separated real numbers in source string''' 
    for text in source.split(): 
     try: 
      val = float(text) 
     except ValueError: 
      pass # ignore non-numbers 
     else: 
      # "NaN", "Inf" get converted: explicit test to ignore them 
      if not math.isnan(val) and not math.isinf(val): 
       yield val 

还有什么我离开原来的东西。

0

如何

for line in tf.readlines(): 
    data =[] 
    for x in line.strip().split(','): 
    if x.replace('.','',1).isdecimal(): 
     data.append(float(x))