Менеджер контекста может необязательно возвращать объект, который будет назначен идентификатору, названному as
. И именно объект, возвращаемый методом __enter__
, назначается as
, а не обязательно самим менеджером контекста.
Использование as <identifier>
помогает при создании нового объекта, как это делает вызов open()
, но не все менеджеры контекста создаются только для контекста. Например, они могут быть многоразовыми и уже созданы.
Воспользуйтесь подключением к базе данных. Вы создаете соединение с базой данных только один раз, но многие адаптеры баз данных позволяют использовать это соединение в качестве менеджера контекста; войдите в контекст, и транзакция запустится, выйдите из него, и транзакция либо будет зафиксирована (в случае успеха), либо откатится (при возникновении исключения):
with db_connection:
# do something to the database
Здесь не нужно создавать новые объекты, вход в контекст осуществляется с помощью db_connection.__enter__()
, а выход из него — с помощью db_connection.__exit__()
, но у нас уже есть ссылка на объект подключения.
Теперь может быть так, что объект подключения создает объект курсора при вводе. Теперь имеет смысл присвоить этому объекту курсора локальное имя:
with db_connection as cursor:
# use cursor to make changes to the database
db_connection
еще не вызывался здесь, он уже существовал раньше, и у нас уже есть ссылка на него. Но все, что произвел db_connection.__enter__()
, теперь назначается cursor
и с этого момента может использоваться.
Это то, что происходит с файловыми объектами; open()
возвращает файловый объект, а fileobject.__enter__()
возвращает файловый объект сам, поэтому вы можете использовать вызов open()
в операторе with
и назначить ссылку на вновь созданный объект в одном шаг, а не два. Без этого маленького трюка вам пришлось бы использовать:
f = open('myfile.txt')
with f:
# use `f` in the block
Применив все это к вашему примеру шейдера; у вас уже есть ссылка на self.shader
. Вполне вероятно, что self.shader.__enter__()
снова возвращает ссылку на self.shader
, но поскольку у вас уже есть вполне пригодная ссылка, зачем создавать для нее новый локальный объект?
person
Martijn Pieters
schedule
13.10.2014
with
, это нормально — см. также, например.contextlib.suppress
. Строго говоря, вы могли бы сделатьwith open(...): ...
, хотя, поскольку тогда вы не можете получить доступ к обработчику файлов, в этом нет особого смысла! - person jonrsharpe   schedule 13.10.2014