Сохранять маржу в 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):

Похоже, косые черты являются допустимым способом обработки этого (но, в конечном счете, ненужным, если вы заключите параметры файла в скобки).

Другие вопросы по тегам