Сохранять маржу в 80 символов долго с заявлением?
Каков питонный путь к PEP-8-ify, такой как с заявлением:
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
Скажите, он автоматически закрывается после с? Это питон?
intemp = tempfile.NamedTemporaryFile(prefix='malt_input.conll.', dir=self.working_dir, mode='w', delete=False)
outtemp = tempfile.NamedTemporaryFile(prefix='malt_output.conll.', dir=self.working_dir, mode='w', delete=False)
with intemp as input_file, outtemp as output_file:
pass
Или я мог бы использовать косые черты:
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
Но соответствует ли этот PEP8? Это питон?
3 ответа
PEP 0008 говорит, что можно использовать обратную косую черту для with
линия.
Обратные слеши могут все еще быть подходящими время от времени. Например, long, множественное с -statements не может использовать неявное продолжение, поэтому обратные слеши допустимы.
Хотя рекомендуется, чтобы они были с отступом, ваша строка должна выглядеть следующим образом:
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 и начинается блок.
Однако вам не нужно использовать косую черту, если вы заключаете параметры в скобки
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
Это, конечно, зависит от вашего точного расположения предложений, и ваш пробег может варьироваться в зависимости от того, лучше ли иметь скобку в конце строки, чем обратную косую черту.
ПКП 8 не слишком ясно об этом. Это только упоминает with
заявление один раз для исключения, когда продолжения обратной косой черты в порядке:
Обратные слеши могут все еще быть подходящими время от времени. Например, long, множественное с -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 здесь. В конце концов, это улучшает читабельность, и это главное.
Btw. обратите внимание, что менеджер контекста может не вернуться 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
Заявление снова становится читабельным.
PEP-8 на самом деле приводит примеры двух похожих ситуаций:
Пример 1 (выглядит наиболее применимым, так как он использует with
заявления):
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())
Пример 2:
class Rectangle(Blob):
def __init__(self, width, height,
color='black', emphasis=None, highlight=0):
Похоже, косые черты являются допустимым способом обработки этого (но, в конечном счете, ненужным, если вы заключите параметры файла в скобки).