2010-06-05 72 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))