Imports Style Guide

в 16:57, , рубрики: python, styleguides, метки: ,

Замечательный PEP8, с которым вы наверняка знакомы, если занимаетесь разработкой на Python, не отвечает на все возникающие в процессе кодинга вопросы. В итоге каждая команда разработчиков берёт PEP8 за основу и вырабатывает собственные стандарты, которых старается придерживаться. Сколько команд – столько вариантов. И это необходимые искусственные рамки. Как сетка для типографа или верстальщика – помогает коду выглядеть чётко, выдержано и последовательно. В общем, форматирование кода – это не то место, где нужно проявлять свою индивидуальность.

Прежде чем задать основной вопрос, уважаемые коллеги, я хотел бы показать некоторые примеры «вольностей», которые каждый принимает для себя сам (или безропотно принимает какое-то чужое решение).

"""
Very long multiline description
about function or class method
"""

лично мне нравится больше, чем

"""Very long multiline description
about function or class method
"""

Расстояние между блоком импортов и первой функцией или классом – 2 пустые строки.

from unittest import TestCase


class BaseURLGeneratorTestCase(TestCase):
    pass

Расстояние между различными функциями или классами – тоже 2 пустые строки. Расстояние между методами класса – 1 пустая строка. Расстояние между заголовком класса и первым методом – 1 пустая строка.

class TestSomething(TestCase):
    
   def test_some_stuff(self):
        pass

   def test_another_stuff(self):
        pass

Перечисление элементов списка/кортежа/словаря и пр. – с каждой новой строки, если всё не влазит в одну:

records = [first_object, second_object]

records = [
    first_object,
    second_object,
    third_object,
    fourth_object,
]

То же касается и длинного логического условия:

if (
    user.is_client()
    and user.has_manager()
    and not user.is_banned()
    and user.has_company()
):
    do_something()

Если есть необходимость разбить цепочку методов на несколько строк, выражение обрамляется в скобки. Никаких бэкслешей (фу-фу-фу).

templates = (
    EmailTemplate.query
    .filter(EmailTemplate.type_id == type.id)
    .order_by(EmailTemplate.title)
    .all()
)

Кортеж из одного элемента записывается как x = (y,) или x = y,, но выглядит это ужасно, поэтому я предпочитаю в данном случае обходиться списком x = [y] или множеством x = {y}, есть и другие варианты.

Проверка на None:

x = None
if x:
    do_something()  # фигня

if x is not None:
    do_something()  # так-то лучше

Кстати, комментарии отбиваются двумя пробелами, а не одним.

Помимо прочего, люблю строковый метод .format(). '{0}'.format(x) мне больше по душе, чем '%s' % x. Но когда точек вставки больше двух, следует использовать именованные аргументы:

'{name} {surname}, {address}'.format(
    name=name,
    surname=surname,
    address=address,
)

Implicit-соединение строк выглядит странно, но визуально приятнее конкатенации сложением:

message = _(
    u"Зачем соединять строки через +, "
    u"если есть вот такая вот фича?"
)

Словарь записываем как {'key': value, 'another_key': another_value}, а не как dict(key=value, another_key=another_value). Это визуально чище, подсвечивается всеми нормальными редакторами как словарь, а не как передача именованных аргументов, к тому же создание такого объекта отрабатывает быстрее, чем через dict().

Таких «пунктиков» наберётся не один десяток и я уверен, что найдутся люди, готовые их оспорить и предложить своё виденье кошерного оформления кода. Но если по приведённым примерам для меня всё более-менее ясно, то по оформлению больших (реально больших) блоков импортов пока не всё очевидно.

Встретил я как-то в рабочем проекте портянку импортов в одном из модулей.

...
from lib.util import https_wrapper, logout_user
from lib.util import ajax, sudo_su, sudo_exit, transactional	
from lib.util import has_auth, get_demo
from lib.util import get_user_registration_source_id
from lib.util import ajax_validate, generate_timed_hash, get_auth_user	
from lib.util import render_template, check_timed_hash
from lib.util import create_validate_response, update_user_in_session	
from lib.util import prepare_watermark_text
...

Подумал про себя: «Какого хрена?..» и переписал так, как нравится мне.

from lib.util import (
    https_wrapper,
    logout_user,
    ajax,
    sudo_su,
    sudo_exit,
    transactional,
    has_auth,
    get_demo,
)

ну вы поняли принцип…

За что отгрёб во время ревью. Как бы предыдущий вариант тоже имеет право на жизнь, удобен во время мёржа и вроде как его удобней читать. Я пообещал аргументировать свой вариант и просто дам ссылку на этот пост, заодно и узнаю что об этом всём думаюте.

Итак. Сама идея «каждый объект с новой строки» важна. Во-первых, это красиво :) Во-вторых, во время мёржа это даёт свои преимущества, путаницы не возникает. Это полезное свойство, нам нужно его сохранить.

Во втором варианте модуль (или пакет) с которого мы импортируем – это как будто заголовок последующего абзаца текста (импортируемых объектов). Нет необходимости каждый раз повторять заголовок, мы уже увидели единожды откуда мы импортируем и у нас есть построчное перечисление чего мы импортируем. Если кому-то надо дополнить список импортов из данного источника, он просто идёт в конец списка, жмёт Enter и дописывает своё (+ запятая, с мыслью о ближнем). Выглядит чище, строки короче, считываются быстрее, не нужно каждый раз дописывать/копипастить источник, который, кстати, может переименоваться. Не нужно игнорировать взглядом часть from bla_bla_bla import для каждой строки. Проскользить глазами 4 пробела намного легче.

Вообще вариантов оформления блока с импортами масса. С десяток, не меньше. Как именно разбивать строки, по каким критериям, сортировать ли по алфавиту, переносить или нет открывающую/закрывающую скобку… Но к какому-то общему знаменателю нужно прийти, вся команда разработчиков должна придерживаться принятого соглашения. Иначе анархия. Знаю людей, которые вообще не заморачиваются на этот счёт, так как в PyCharm есть чудесный автоимпорт и есть точка зрения, что совсем неважно что творится в этом блоке. Но у нас команда большая, PyCharm использую по ходу только я (большинство на Sublime, остальные – Vim, Emacs, Eclipse), нужно позаботиться о том, чтобы всем было удобно и понятно. Ну и с моей точки зрения, импорты – тоже код, который достоен хорошо выглядеть. Maintainability, в конце концов. А что думаете вы?

Итак, опрос.

Как оформлять блок с импортами?

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Никто ещё не голосовал. Воздержавшихся нет.

Автор: artifex

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js