open withステートメントを使用してファイルを開く方法


200

Pythonでファイルの入出力を行う方法を探しています。ファイル内の名前に対して名前をチェックし、ファイル内の出現箇所にテキストを追加しながら、名前のリスト(1行に1つ)をファイルから別のファイルに読み取る次のコードを書きました。コードは機能します。それはもっとうまくできるでしょうか?

with open(...ステートメントを入力ファイルと出力ファイルの両方に使用したかったのですが、それらが同じブロック内にどのように配置されるかを確認できません。つまり、一時的な場所に名前を保存する必要があります。

def filter(txt, oldfile, newfile):
    '''\
    Read a list of names from a file line by line into an output file.
    If a line begins with a particular name, insert a string of text
    after the name before appending the line to the output file.
    '''

    outfile = open(newfile, 'w')
    with open(oldfile, 'r', encoding='utf-8') as infile:
        for line in infile:
            if line.startswith(txt):
                line = line[0:len(txt)] + ' - Truly a great person!\n'
            outfile.write(line)

    outfile.close()
    return # Do I gain anything by including this?

# input the name you want to check against
text = input('Please enter the name of a great person: ')    
letsgo = filter(text,'Spanish', 'Spanish2')

「名前を一時的な場所に保存する必要がある」という意味ですか?これの意味を説明できますか?
S.Lott

4
注意filter()された組み込み関数 、あなたはおそらく、あなたの関数に別の名前を選択する必要がありますので。
トム

2
@Tom名前空間の関数は組み込み関数をオーバーライドしますか?
UpTide 2017年

2
@UpTide:はい、PythonはLEGBの順序で動作します-ローカル、囲み、グローバル、組み込み(stackoverflow.com/questions/291978/…を参照)。したがって、グローバル関数(filter())を作成すると、組み込み関数の前に見つかりますfilter()
Tom

回答:


308

Pythonではopen()、1つのに複数のステートメントを配置できますwith。それらをカンマで区切ります。コードは次のようになります。

def filter(txt, oldfile, newfile):
    '''\
    Read a list of names from a file line by line into an output file.
    If a line begins with a particular name, insert a string of text
    after the name before appending the line to the output file.
    '''

    with open(newfile, 'w') as outfile, open(oldfile, 'r', encoding='utf-8') as infile:
        for line in infile:
            if line.startswith(txt):
                line = line[0:len(txt)] + ' - Truly a great person!\n'
            outfile.write(line)

# input the name you want to check against
text = input('Please enter the name of a great person: ')    
letsgo = filter(text,'Spanish', 'Spanish2')

そして、いいえ、あなたはreturnあなたの関数の最後に明示を置くことによって何も得ません。を使用returnして早期終了することができますが、最後に終了したため、関数はそれなしで終了します。(もちろん、値を返す関数では、を使用して、return返す値を指定します。)

ステートメントが導入されたときのPython 2.5 またはPython 2.6では、複数のopen()項目の使用withはサポートされていませんでしwithたが、Python 2.7およびPython 3.1以降ではサポートされています。

http://docs.python.org/reference/compound_stmts.html#the-with-statement http://docs.python.org/release/3.1/reference/compound_stmts.html#the-with-statement

Python 2.5、2.6、または3.0で実行する必要があるコードをwith記述している場合は、他の回答が示唆するようにステートメントをネストするか、を使用してくださいcontextlib.nested


28

このようにネストされたブロックを使用し、

with open(newfile, 'w') as outfile:
    with open(oldfile, 'r', encoding='utf-8') as infile:
        # your logic goes right here

12

あなたはあなたのブロックを入れ子にすることができます。このような:

with open(newfile, 'w') as outfile:
    with open(oldfile, 'r', encoding='utf-8') as infile:
        for line in infile:
            if line.startswith(txt):
                line = line[0:len(txt)] + ' - Truly a great person!\n'
            outfile.write(line)

これはoutfile、コードで例外が発生した場合でも閉じられることを保証するため、バージョンよりも優れています。明らかに、try / finallyでそれを行うことができますwithが、これを行う正しい方法です。

または、先ほど学んだように、@ stevehaで説明されているように、withステートメントに複数のコンテキストマネージャーを含めることができます。それはネストよりも良いオプションのようです。

そして、あなたの最後の小さな質問については、リターンは実際の目的を果たしません。削除します。


どうもありがとう。私はそれを試してみて、私がそれを機能させるようになったときに/あなたの答えを受け入れます。
Disnami

再度、感謝します。私が受け入れることができる前に、7つのミントを待たなければなりません。
Disnami

7
@Disnamiは、正しい答えを受け入れるようにしてください(これはこれではありません!);-)
David Heffernan

1

場合によっては、さまざまな量のファイルを開いて、それぞれを同じように扱いたい場合があります。これを行うには、 contextlib

from contextlib import ExitStack
filenames = [file1.txt, file2.txt, file3.txt]

with open('outfile.txt', 'a') as outfile:
    with ExitStack() as stack:
        file_pointers = [stack.enter_context(open(file, 'r')) for file in filenames]                
            for fp in file_pointers:
                outfile.write(fp.read())                   
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.