Як відкрити файл за допомогою оператора open з оператором


201

Я дивлюся на те, як зробити введення та виведення файлів у 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')

"значить мені потрібно зберігати імена у тимчасовому місці"? Чи можете ви пояснити, що ви маєте на увазі під цим?
S.Lott

4
Зауважте, що filter()це вбудована функція, і тому ви, ймовірно, повинні вибрати іншу назву для своєї функції.
Том

2
@ Чи функція в просторі імен замінює вбудовану функцію?
UpTide

2
@UpTide: Так, Python працює в порядку LEGB - Local, Enclosing, Global, Built-in (див. Stackoverflow.com/questions/291978/… ). Отже, якщо ви зробите глобальну функцію ( filter()), вона буде знайдена перед вбудованимfilter()
Том

Відповіді:


309

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.


29

Використовуйте такі вкладені блоки,

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її буде закрито, навіть якщо ваш код зустріне винятки. Очевидно, ви могли це зробити за допомогою спробуйте / нарешті, але withце правильний спосіб зробити це.

Або, як я нещодавно дізнався, ви можете мати декілька контекстних менеджерів в операторі із заявою, як описано в @steveha . Мені здається, це кращий варіант, ніж гніздування.

І для вашого останнього другорядного питання повернення не служить реальній меті. Я б її зняв.


Дуже дякую. Я спробую це і прийму вашу відповідь, якщо / коли я змушу її працювати.
Disnami

Знову дякую. Доведеться чекати сім карток, перш ніж я можу прийняти.
Disnami

7
@Disnami переконайтесь, що ви приймаєте правильну відповідь (і це не ця!) ;-)
Девід Геффернан

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())                   
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.