Подтвердить что ты не робот

Понимание инструкции Python с выражением

Я пытаюсь понять, есть ли разница между ними и какая разница.

Вариант один:

file_obj = open('test.txt', 'r')

with file_obj as in_file:
    print in_file.readlines()

Вариант второй:

with open('test.txt', 'r') as in_file:
    print in_file.readlines()

Я понимаю, что с Вариантом Один, file_obj находится в закрытом состоянии после блока с.

4b9b3361

Ответ 1

Я не знаю, почему никто еще не упомянул об этом, потому что он фундаментален для способ with работает. Как и во многих языковых функциях в Python, with за кулисами вызывает специальные методы, которые уже определены для встроенных объектов Python и могут быть переопределяется определяемыми пользователем классами. В with конкретном случае (и в контекстных менеджерах в целом) методы __enter__ и __exit__.

Помните, что в Python все это объект - даже литералы. Вот почему вы можете делать такие вещи, как 'hello'[0]. Таким образом, не имеет значения, используете ли вы файл файл непосредственно в качестве возвращаемого open:

with open('filename.txt') as infile:
    for line in infile:
        print(line)

или сначала сохраните его с другим именем (например, чтобы разбить длинную строку):

the_file = open('filename' + some_var + '.txt')
with the_file as infile:
    for line in infile:
        print(line)

Потому что конечным результатом является the_file, infile, а возвращаемое значение open все указывает на один и тот же объект и что with вызывает методы __enter__ и __exit__ на, Встроенный метод объекта закрывает файл.

Ответ 2

Они ведут себя одинаково. Как правило, значение кода Python не изменяется, присваивая выражение переменной в той же области видимости.

Это по той же причине, что они идентичны:

f = open("myfile.txt")

против

filename = "myfile.txt"
f = open(filename)

Независимо от того, добавляете ли вы псевдоним, значение кода остается неизменным. Диспетчер контекста имеет более глубокий смысл, чем передача аргумента функции, но принцип тот же: маска управления контекстом применяется к одному и тому же объекту, и файл закрывается в обоих случаях.

Единственная причина выбора одного над другим - если вы чувствуете, что это помогает ясности кода или стиля.

Ответ 3

Нет никакой разницы между двумя способами: любой способ закрыть файл при выходе из блока.

Второй пример, который вы даете, - это типичный способ использования файлов в Python 2.6 и более поздних версиях (когда был добавлен синтаксис with).

Вы можете проверить, что первый пример также работает в сеансе REPL следующим образом:

>>> file_obj = open('test.txt', 'r')
>>> file_obj.closed
False
>>> with file_obj as in_file:
...     print in_file.readlines()
<Output>
>>> file_obj.closed
True

Итак, после выхода блоков with, файл закрыт.

Обычно второй пример - это то, как вы это делаете.

Нет причин создавать эту дополнительную переменную file_obj... все, что вы могли бы сделать с ней после окончания блока with, который вы могли бы просто использовать in_file для, потому что он все еще в области видимости.

>>> in_file
<closed file 'test.txt', mode 'r' at 0x03DC5020>

Ответ 4

Если вы просто запускаете Python и используете любой из этих параметров, то сетевой эффект будет таким же, если базовый экземпляр объекта Python file не изменяется. (В варианте 1 файл закрывается только тогда, когда file_obj выходит за пределы области действия vs в конце блока во втором варианте, как вы уже заметили.)

Однако могут быть различия с вариантами использования с менеджером контекста. Поскольку file является объектом, вы можете изменить его или подклассировать его.

Вы также можете открыть файл, просто позвонив file(file_name), показывая, что file действует как другие объекты (но никто не открывает файлы таким образом в Python, если он не с with):

>>> f=open('a.txt')
>>> f
<open file 'a.txt', mode 'r' at 0x1064b5ae0>
>>> f.close()

>>> f=file('a.txt')
>>> f
<open file 'a.txt', mode 'r' at 0x1064b5b70>
>>> f.close()

В общем случае открытие и закрытие некоторого ресурса, называемого the_thing (обычно файл, но может быть любым), вы выполняете следующие действия:

set up the_thing                       # resource specific, open, or call the obj
try                                    # generically __enter__
    yield pieces from the_thing
except
    react if the_thing is broken 
finally, put the_thing away            # generically __exit__

Вы можете с легкостью изменить поток этих подэлементов с помощью диспетчера контекста и процедурного кода, сплетенного между open и другими элементами кода.

Так как Python 2.5, файловые объекты имеют методы __enter__ и __exit__:

>>> f=open('a.txt')
>>> f.__enter__
<built-in method __enter__ of file object at 0x10f836780>
>>> f.__exit__
<built-in method __exit__ of file object at 0x10f836780>

Объект Python file по умолчанию использует эти методы таким образом:

__init__(...)            # performs initialization desired

__enter__() -> self      # in the case of `file()` return an open file handle

__exit__(*excinfo) -> None.  # in the case of `file()` closes the file.

Эти методы могут быть изменены для вашего собственного использования, чтобы изменить способ обращения с ресурсом при его открытии или закрытии. Диспетчер контекста позволяет очень легко изменять, что происходит, когда вы открываете или закрываете файл.

Тривиальный пример:

class Myopen(object):
    def __init__(self, fn, opening='', closing='', mode='r', buffering=-1):
        # set up the_thing

        if opening:
            print(opening)
        self.closing=closing    
        self.f=open(fn, mode, buffering)

    def __enter__(self):
        # set up the_thing
        # could lock the resource here
        return self.f

    def __exit__(self, exc_type, exc_value, traceback):
        # put the_thing away
        # unlock, or whatever context applicable put away the_thing requires
        self.f.close()
        if self.closing:
            print(self.closing)  

Теперь попробуйте следующее:

>>> with Myopen('a.txt', opening='Hello', closing='Good Night') as f:
...     print f.read()
...
Hello
[contents of the file 'a.txt']
Good Night

Как только вы контролируете запись и выходите на ресурс, существует много вариантов использования:

  • Заблокировать ресурс для доступа к нему и использовать его; разблокировать, когда вы закончите.
  • Сделать причудливый ресурс (например, файл памяти, базу данных или веб-страницу) более похожи на прямой файловый ресурс
  • Откройте базу данных и откат, если есть исключение, но совершите все записи, если ошибок нет.
  • Временное изменение контекста вычисления с плавающей запятой
  • Время фрагмента кода
  • Измените исключения, которые вы повышаете, возвращая True или False из метода __exit__.

Вы можете прочитать больше примеров в PEP 343.