Как открыть файл с помощью оператора open with - PullRequest
178 голосов
/ 14 февраля 2012

Я смотрю, как сделать файл ввода и вывода в 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')

Ответы [ 4 ]

277 голосов
/ 14 февраля 2012

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.

24 голосов
/ 14 февраля 2012

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

with open(newfile, 'w') as outfile:
    with open(oldfile, 'r', encoding='utf-8') as infile:
        # your logic goes right here
10 голосов
/ 14 февраля 2012

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

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 является правильным способом сделать это.

Или, как я только что узнал, вы можете иметь несколько менеджеров контекста в операторе with как описывается @ steveha .Мне кажется, это лучший вариант, чем вложение.

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

1 голос
/ 05 марта 2019

Иногда вам может понадобиться открыть переменное количество файлов и обрабатывать каждый из них одинаково, вы можете сделать это с помощью 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())                   
...