2012-12-20 44 views
0

我有以下功能。該程序查看每個文件並將所有4個文件中出現的行打印到新文件中。我試過file1.close(),但是我收到關於關閉一個集合的錯誤?我想我可以使用with聲明,但不知道如何做到這一點,我對編程非常陌生。如何關閉此功能中使用的文件?

def secretome(): 
    file1 = set(line.strip() for line in open(path + "goodlistSigP.txt")) 
    file2 = set(line.strip() for line in open(path + "tmhmmGoodlist.txt")) 
    file3 = set(line.strip() for line in open(path + "targetpGoodlist.txt")) 
    file4 = set(line.strip() for line in open(path + "wolfPsortGoodlist.txt")) 
    newfile = open(path + "secretome_pass.txt", "w") 
    for line in file1 & file2 & file3 & file4: 
     if line: 
      newfile.write(line + '\n') 
    newfile.close() 

回答

4

我建議通過抽取您所設定的代入功能刪除重複:

def set_from_file(path): 
    with open(path) as file: 
     return set(lines.strip() for line in file) 

def secretome(): 
    files = ["goodlistSigP.txt", "tmhmmGoodlist.txt", "targetpGoodlist.txt", "wolfPsortGoodlist.txt"] 
    data = [set_from_file(os.path.join(path, file)) for file in files] 
    with open(path + "secretome_pass.text", "w") as newfile: 
     newfile.writelines(line + "/n" for line in set.union(*data) if line) 

注意,你在你的代碼做交集,但你說說想要一個工會,所以我用union()在這裏。還有一些list comprehensions/generator expressions

+0

我認爲你的newfile沒有換行符。否則,很好的答案。打了我一分鐘左右。 – mgilson

+2

作爲一個方面說明,也許'newfile.writelines(行+'\ n'行...如果行)'可能會更清潔 – mgilson

+0

@mgilson好的建議,我會做出更改。 –

0

你可以把它變成一個發電機:

def closingfilelines(*a): 
    with open(*a) as f: 
     for line in f: 
      yield f 

,並使用它,你目前使用的open()

生成器運行時,文件保持打開狀態,如果生成器耗盡,它將被關閉。

同樣的情況,如果發電機對象是.close() d或下降 - 在這種情況下,發電機得到一個GeneratorExit例外,這使得with子句離開爲好。

+1

我不認爲'open(* a)'是你想要的東西......是嗎? – mgilson

+0

@mgilson爲什麼不呢?所以我可以在OP中設置(line.strip()爲closefile(path +「goodlistSigP.txt」))中的行,以及'closefilelines(path +「goodlistSigP.txt」,「r + b 「,1024)'如果需要的話。 – glglgl

+0

不可否認,我的解決方案並不如那些在其函數中包含'set()'構建的解決方案,但它不是很糟糕,是嗎? – glglgl

1

藉此完全不同的方向上比我原來的(這Lattyware打我):

你可以定義一個函數:

def file_lines(fname): 
    with open(fname) as f: 
     for line in f: 
      yield line 

現在你可以使用itertools.chain遍歷文件:

import itertools 
def set_from_file(path): 
    filenames = ("name1","name2","name3",...) #your input files go here 
    lines = itertools.chain.from_iterable(itertools.imap(file_lines,filenames)) 
    #lines is an iterable object. 
    #At this point, virtually none of your system's resources have been consumed 
    with open("output",'w') as fout: 
     #Now we only need enough memory to store the non-duplicate lines :) 
     fout.writelines(set(line.strip()+'\n' for line in lines)) 
+0

+1,一個很好的解決方案,雖然請注意它不會刪除像原來的重複。 –

+0

@Lattyware - 爲什麼不能重複刪除?在一天結束時,每個文件的每一行都被傳遞給一個傳遞給'writelines'的集合。 – mgilson

+0

無視我,你是完全正確的。 –

1

這似乎是一個非常複雜的做法。我會建議像我在這裏給出的例子。

import fileinput 
files = ['file1.txt','file2.txt','file3.txt','file4.txt'] 
output = open('output.txt','w') 

for file in files: 
    for line in fileinput.input([file]): 
     output.write(line) 
    output.write('\n') 

output.close() 

此代碼創建與它的文件(更換所需的文件路徑名)的列表,創建一個文件來存儲每個輸出,然後簡單地通過他們迭代使用的FileInput模塊要經過各一行一行地逐行打印每行到輸出文件。 'output.write('\ n')'確保下一個文件行的打印從輸出文件的新行開始。

+0

爲什麼不直接在'fileinput.input(list):'中插入行,但這裏的想法是堅實的(我非常喜歡它)。這基本上是我使用'itertools'在我的答案中複製的(忘記了'fileinput')。唯一不利的一面是,它並不能真正幫助OP瞭解上下文管理器。另外,請不要使用'list'作爲變量名,並且請使用'open'打開一個文件。 – mgilson

+0

一個很好的解決方案,儘管注意它不會刪除像原始文件這樣的重複文件,但也要注意,如mgilson所說,打開文件的'file()'是個壞主意。另外,你應該真的使用'with'語句。 –

+0

是的,你是正確的名單作爲一個變量的名字好吧,我的文化。至於在fileinput.input(list)中使用'for line',這將不允許在每個文件的最後一行的末尾添加換行符,這可能意味着新文件的第一行將是打印在與前一行最後一行相同的行上。 –