Как открыть файл с помощью оператора open with

Я смотрю, как делать ввод и вывод файлов в Python. Я написал следующий код, чтобы прочитать список имен (по одному в строке) из файла в другой файл, проверяя имя на имена в файле и добавляя текст к вхождениям в файл. Код работает. Это можно сделать лучше?

Я хотел использовать инструкцию 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')

Ответ 1

Python позволяет размещать несколько операторов open() в одном 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 для указания возвращаемого значения.)

Использование нескольких элементов open() с with не поддерживалось в Python 2.5, когда был введен оператор with или в Python 2.6, но он поддерживается в 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.

Ответ 2

Используйте такие вложенные блоки,

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

Ответ 3

Вы можете вложить свои блоки с помощью блоков. Вот так:

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. Это кажется мне лучшим вариантом, чем гнездование.

И для вашего последнего второстепенного вопроса возвращение не имеет реальной цели. Я бы удалил его.