PEP 8 не слишком понятно об этом. Он упоминает только with
заявления раз за исключение, когда backslashe продолжений в порядке:
Обратных косые все еще могут быть целесообразными в разы.Например, длинный, многократная с -statements не может использовать неявное продолжение, поэтому обратные косые являются приемлемыми:
with open('/path/to/some/file/you/want/to/read') as file_1, \
open('/path/to/some/file/being/written', 'w') as file_2:
file_2.write(file_1.read())
способом преодолеть эту проблему будет действительно сначала сделать вызов функции, которая возвращает менеджер контекста, а затем просто использовать это непосредственно, как вы уже предложили в вашем вопросе:
file_1 = open('/path/to/some/file/you/want/to/read')
file_2 = open('/path/to/some/file/being/written', 'w')
with file_1, file_2:
file_2.write(file_1.read())
Это прекрасно работает (потому что with
заявление будет просто вызывать методы из контекста менеджера, независимо от того, откуда она пришла), а также закрывает ручки правильно ,
Однако это явно запрещено в PEP 8:
менеджеры Контекст должен вызываться через отдельные функции или методы, когда они делают что-то другое, чем приобретать и освободить ресурсы. Не Например:
Да:
with conn.begin_transaction():
do_stuff_in_transaction(conn)
№:
with conn:
do_stuff_in_transaction(conn)
Последний пример не дает никакой информации, указывающей, что __enter__
и __exit__
методы делают нечто иное, чем закрыть соединение после транзакции. В этом случае важно быть явным.
Таким образом, в конце концов, кажется, нет никакого реального решения, которое позволило по PEP 8. И в этот момент, я бы сказал, что это прекрасно, чтобы «нарушить его» и идти против него: Это просто стиль руководство.
В то время как это предлагает много хороших правил, есть также много ситуаций, в которых просто не имеет смысла следовать им строго. Я бы сказал, что ваш пример использования косой черты едва читаемый, и вы, вероятно, можете прочитать это намного лучше, если бы вы позволили более длинным строки и просто сломали линию один раз в контекст менеджер:
with tempfile.NamedTemporaryFile(prefix='malt_input.conll.', dir=self.working_dir, mode='w', delete=False) as input_file, \
tempfile.NamedTemporaryFile(prefix='malt_output.conll.', dir=self.working_dir, mode='w', delete=False) as output_file:
pass
Да, вам может понадобиться для прокрутки для этого, но по крайней мере вы можете очень четко видеть, что происходит.
Другой альтернативой было бы на самом деле инициализировать объекты непосредственно перед with
:
malt_input = tempfile.NamedTemporaryFile(prefix='malt_input.conll.', dir=self.working_dir, mode='w', delete=False)
malt_output = tempfile.NamedTemporaryFile(prefix='malt_output.conll.', dir=self.working_dir, mode='w', delete=False)
with malt_input as input_file, malt_output as output_file:
pass
Поскольку вы делаете это непосредственно перед with
, оно должно быть приемлемым исключение из правила PEP 8 здесь. В конце концов, это улучшает читаемость, и это важно.
КПП. обратите внимание, что диспетчер контекста не может возвращать self
по адресу __enter__
, поэтому вы должны использовать синтаксис as
, чтобы присвоить возвращаемое значение диспетчера контекста переменной.
Наконец, один другой вариант, который будет работать на вашей конкретной ситуации, было бы обернуть вызов в отдельную функцию:
def namedTemp(prefix):
return tempfile.NamedTemporaryFile(prefix=prefix,
dir=self.working_dir, mode='w', delete=False)
with namedTemp('malt_input.conll.') as input_file, \
namedTemp('malt_output.conll.') as output_file:
pass
Так в основном, абстрактные все прочь, так что with
заявление снова становится читаемым.
В разделе [PEP8] (https://www.python.org/dev/peps/pep-0008/#maximum-line-length) имеется раздел о максимальных длинах строк – GP89
[Beyond PEP8] (https: // www.youtube.com/watch?v=wf-BqAjZb8M)! – mkrieger1
Возможный дубликат [Как разбить длинный оператор с помощью python] (http://stackoverflow.com/questions/16080049/how-to-break-a-long-with-statement-in-python) – mkrieger1