Для чего оформлять код в python пакеты
Перейти к содержимому

Для чего оформлять код в python пакеты

  • автор:

Упаковать код

Код можно загрузить через панель управления или API. Можно использовать один файл или загрузить пакет (модуль) архивом.

Python ⁠ ​

Код одним файлом ⁠ ​

Создайте файл с функцией без импорта сторонних пакетов:

def handler(**kwargs): return f"Hello, kwargs>" 

Код одним файлом с библиотеками для обработки изображений ⁠ ​

В среде выполнения Python предустановлены различные пакеты и библиотеки, которые оптимизированы для обработки изображений:

  • Pillow;
  • opencv-python с нужными стандартными библиотеками;
  • pyzbar с libzbar;
  • numpy;
  • imutils.

К этим библиотекам можно обращаться, загрузив исходный код в виде одного файла.

Код в виде пакета (модуль) ⁠ ​

Загрузка кода в виде пакета позволяет включить не только несколько файлов проекта, но и указать его зависимости. Перед загрузкой через панель управления или API пакет следует заархивировать (.zip или .tar*).

Для создания python-пакета используйте инструкцию Packaging Python Projects. Для установки пакетов и их зависимостей используется менеджер pip.

Node.js ⁠ ​

Код одним файлом ⁠ ​

Создайте файл с функцией без импорта сторонних библиотек:

module.exports.main = (event) =>   return `Hello, $event>` > 

Код в виде пакета (модуль) ⁠ ​

Загрузка кода в виде пакета позволяет включить не только несколько файлов проекта, но и указать его зависимости. Перед загрузкой через панель управления или API пакет следует заархивировать (.zip или .tar*).

Создайте папку и добавьте в неё файлы с вашим кодом и package.json, в котором указаны зависимости. Затем заархивируйте папку (.zip или .tar*) и загрузите архив через панель управления или API.

  • Python
    • Код одним файлом
    • Код одним файлом с библиотеками для обработки изображений
    • Код в виде пакета (модуль)
    • Код одним файлом
    • Код в виде пакета (модуль)

    Python модули и пакеты

    При написании объёмного кода, часто прибегают к разбиению такового на логически независимые блоки и к последующему выносу в другие файлы. Это повышает читаемость как самого кода, так и проекта целиком. Что влечет за собой менее ресурсозатратную поддержку(дальнейшую модификацию кодовой базы для разных нужд).

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

    Модули также могут быть написаны и на других языках, но данная статья направлена на рассмотрение использования данного механизмах в рамках Python.

    Модули

    В языке программирования Python модулями являются все файлы с расширением *.py (* обозначает, что на этом месте может стоять любой символ или любое их количество). Исключением является служебный файл __init__.py (о назначении которого описано далее в статье).

    Дальше стоит понимать, что любая программа имеет некую точку входа. Это своего рода место с которого стартует наш скрипт. В языках предшественниках данной точкой служила функция main и могла быть лишь только одной. В нашем случае допускается отсутствие таковой, но это снижает качество кода, делая его сложным и малопредсказуемым(при импорте код содержащийся на верхнем уровне исполняется). Для того чтобы указать точку входа(может быть указана только в модулях) используется специальная переменная __name__ , в которой содержится наименование текущего модуля или пакета. Если текущий модуль находится на верхнем уровне исполнения(мы явно его передали на исполнение Python), то он называется __main__ независимо от названия файла.

    # Указание входной точки ## Если __name__ равно "__main__" исполни if __name__ == "__main__": print('Я главный!') # Вызов других функций, например main()

    Для примера реализуем простой модуль, который будет возвращать нам информацию:

    # http_get.modules.http_get # Расположен в дирректории http_get, modules и назван http_get def get_dict(): return # Поскольку зависимых импортов нет, мы можем исполнить этот код для проверки # Т.е. в качестве входной точки использовать нашу функцию # Данный код исполнится только, когда этот файл будет исполняемым(не импортируемым) if __name__ == '__main__': print(get_dict())

    Далее в корне создадим main.py файл, в который импортируем наш модуль двумя разными способами(об импортах описано в статье):

    # main.py from ModulesAndPackages.module_examples.http_get.modules.http_get import get_dict as absolute from http_get.modules.http_get import get_dict as relative def main(): # Работает print(absolute()) print(relative()) if __name__ == '__main__': main()

    Все без проблем исполняется.

    Трудности

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

    Не изменяя наши модули(импорты), при изменении положения файлов возникает ошибка импорта:

    # Не работает в другом проекте from ModulesAndPackages.module_examples.http_get.modules.http_get import get_dict as absolute # Всегда работает from http_get.modules.http_get import get_dict as relative def main(): print(absolute()) print(relative()) if __name__ == '__main__': main()

    Пакеты

    В языке программирования Python пакетами являются все директории(вне зависимости от наличия в них модулей), содержащие файл __init__.py , который исполняется при импорте пакета и несет его название ( __name__ ).

    Для примера реализуем простой пакет( package ), на базе вышеописанного модуля( http_get.py ):

    # package/modules/http_get.py def get_dict(): return if __name__ == '__main__': print(get_dict())
    # package/__init__.py from .modules.http_get import get_dict . def get_data(): return get_dict() . # Не работает # __init__ не может иметь точки входа # # if __name__ == '__main__': # get_data()

    А также реализуем простой пакет с такой же логикой, но с использованием абсолютного импорта:

    # package_2/modules/http_get.py def get_dict(): return if __name__ == '__main__': print(get_dict()) 
    # package_2/__init__.py from ModulesAndPackages.package_examples.package_2.modules.http_get import get_dict . def get_data(): return get_dict() . # Не работает # __init__ не может иметь точки входа # # if __name__ == '__main__': # get_data()

    В корне директории(на уровень выше пакета) создадим файл, в котором воспользуемся нашими пакетами( main.py ):

    # main.py from package import get_data from package_2 import get_data as get_data_2 def main(): # Работает print(get_data()) print(get_data_2()) if __name__ == '__main__': main()

    Все работает без ошибок.

    Трудности

    Но при переносе нашего package_2 в другой проект, он теряет свою работоспособность из-за ошибки импортирования в __init__.py файле, в отличии от package .

    # package_transferring/package/modules/http_get.py def get_dict(): return if __name__ == '__main__': print(get_dict())
    # package_transferring/package/__init__.py from .modules.http_get import get_dict . def get_data(): return get_dict() . # Не работает # __init__ не может иметь точки входа # # if __name__ == '__main__': # get_data()
    # package_transferring/package_2/modules/http_get.py def get_dict(): return if __name__ == '__main__': print(get_dict())
    # package_transferring/package_2/__init__.py # Ошибка импорта т.к. изменилась директория from ModulesAndPackages.package_examples.package_2.modules.http_get import get_dict . def get_data(): return get_dict() . # Does not work! # Because init file in package could not have entry point # # if __name__ == '__main__': # get_data()
    # package_transferring/main.py from package import get_data # Ошибка импорта from package_2 import get_data as get_data_2 def main(): print(get_data()) print(get_data_2()) if __name__ == '__main__': main()

    P.S.

    Данная статья написана для новичков, которые изучают язык программирования Python. Задача которой продемонстрировать на простых примерах способы написания пакетов и модулей(не является туториалом), а так же показать какие трудности могут возникнуть и пути их решения.

    Github с проектом к данной статье: ModulesAndPackages

    Может быть полезно выгрузить модуль или пакет и попробовать внедрить его в свой проект.

    Как организовать код в Python-проекте, чтобы потом не пожалеть

    Python отличается от таких языков программирования, как C# или Java, заставляющих программиста давать классам имена, соответствующие именам файлов, в которых находится код этих классов.

    Python — это самый гибкий язык программирования из тех, с которыми мне приходилось сталкиваться. А когда имеешь дело с чем-то «слишком гибким» — возрастает вероятность принятия неправильных решений.

    • Хотите держать все классы проекта в единственном файле main.py ? Да, это возможно.
    • Надо читать переменную окружения? Берите и читайте там, где это нужно.
    • Требуется модифицировать поведение функции? Почему бы не прибегнуть к декоратору!?

    Применение многих идей, которые легко реализовать, может привести к негативным последствиям, к появлению кода, который очень тяжело поддерживать.

    Но, если вы точно знаете о том, что делаете, последствия гибкости Python не обязательно окажутся плохими.

    Здесь я собираюсь представить вашему вниманию рекомендации по организации Python-кода, которые сослужили мне хорошую службу, когда я работал в разных компаниях и взаимодействовал со многими людьми.

    Структура Python-проекта

    Сначала обратим внимание на структуру директорий проекта, на именование файлов и организацию модулей.

    Рекомендую держать все файлы модулей в директории src , а тесты — в поддиректории tests этой директории:

     ├── src │ ├── /* │ │ ├── __init__.py │ │ └── many_files.py │ │ │ └── tests/* │ └── many_tests.py │ ├── .gitignore ├── pyproject.toml └── README.md

    Здесь — это главный модуль проекта. Если вы не знаете точно — какой именно модуль у вас главный — подумайте о том, что пользователи проекта будут устанавливать командой pip install , и о том, как, по вашему мнению, должна выглядеть команда import для вашего модуля.

    Часто имя главного модуля совпадает с именем всего проекта. Но это — не некое жёсткое правило.

    Аргументы в пользу директории src

    Я видел множество проектов, устроенных по-другому.

    Например, в проекте может отсутствовать директория src , а все модули будут просто лежать в его корневой директории:

    non_recommended_project ├── /* │ ├── __init__.py │ └── many_files.py │ ├── .gitignore │ ├── tests/* │ └── many_tests.py │ ├── pyproject.toml │ ├── /* │ ├── __init__.py │ └── many_files.py │ └── README.md

    Уныло смотрится проект, в структуре которого нет никакого порядка из-за того, что его папки и файлы просто расположены по алфавиту, в соответствии с правилами сортировки объектов в IDE.

    Главная причина, по которой рекомендуется пользоваться папкой src , заключается в том, чтобы активный код проекта был бы собран в одной директории, а настройки, параметры CI/CD, метаданные проекта находились бы за пределами этой директории.

    Единственный минус такого подхода заключается в том, что, без дополнительных усилий, не получится воспользоваться в своём коде командой вида import module_a . Для этого потребуется кое-что сделать. Ниже мы поговорим о том, как решить эту проблему.

    Именование файлов

    Правило №1: тут нет файлов

    Во-первых — в Python нет таких сущностей, как «файлы», и я заметил, что это — главный источник путаницы для новичков.

    Если вы находитесь в директории, содержащей файл __init__.py , то это — директория, включающая в себя модули, а не файлы.

    Рассматривайте каждый модуль, как пространство имён.

    Я говорю о «пространстве имён», так как нельзя сказать с уверенностью — имеется ли в модуле множество функций и классов, или только константы. В нём может присутствовать практически всё что угодно, или лишь несколько сущностей пары видов.

    Правило №2: если нужно — держите сущности в одном месте

    Совершенно нормально, когда в одном модуле имеется несколько классов. Так и стоит организовывать код (но, конечно, только если классы связаны с модулем).

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

    Часто встречается мнение, что это — пример неудачного приёма работы. Те, кто так считают, находятся под влиянием опыта, полученного после использования других языков программирования, которые принуждают к другим решениям (например — это Java и C#).

    Правило №3: давайте модулям имена, представляющие собой существительные во множественном числе

    Давая модулям имена, следуйте общему правилу, в соответствии с которым эти имена должны представлять собой существительные во множественном числе. При этом они должны отражать особенности предметной области проекта.

    Правда, у этого правила есть и исключение. Модули могут называться core , main.py или похожим образом, что указывает на то, что они представляют собой некую единичную сущность. Подбирая имена модулей, руководствуйтесь здравым смыслом, а если сомневаетесь — придерживайтесь вышеприведённого правила.

    Реальный пример именования модулей

    Вот мой проект — Google Maps Crawler, созданный в качестве примера.

    Этот проект направлен на сбор данных из Google Maps с использованием Selenium и на их представление в виде, удобном для дальнейшей обработки (тут, если интересно, можно об этом почитать).

    Вот текущее состояние дерева проекта (тут выделены исключения из правила №3):

    gmaps_crawler ├── src │ └── gmaps_crawler │ ├── __init__.py │ ├── config.py (форма единственного числа) │ ├── drivers.py │ ├── entities.py │ ├── exceptions.py │ ├── facades.py │ ├── main.py (форма единственного числа) │ └── storages.py │ ├── .gitignore ├── pyproject.toml └── README.md

    Весьма естественным кажется такой импорт классов и функций:

    from gmaps_crawler.storages import get_storage from gmaps_crawler.entities import Place from gmaps_crawler.exceptions import CantEmitPlace

    Можно понять, что в exceptions может иметься как один, так и множество классов исключений.

    Именование модулей существительными множественного числа отличается следующими приятными особенностями:

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

    Именование классов, функций и переменных

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

    Имена функций и методов должны быть глаголами

    Функции и методы представляют собой действия, или нечто, выполняющее действия.

    Функция или метод — это не просто нечто «существующее». Это — нечто «действующее».

    Действия чётко определяются глаголами.

    Вот — несколько удачных примеров из реального проекта, над которым я раньше работал:

    def get_orders(): . def acknowledge_event(): . def get_delivery_information(): . def publish(): . 

    А вот — несколько неудачных примеров:

    def email_send(): . def api_call(): . def specific_stuff(): . 

    Тут не очень ясно — возвращают ли функции объект, позволяющий выполнить обращение к API, или они сами выполняют какие-то действия, например — отправку письма.

    Я могу представить себе такой сценарий использования функции с неудачным именем:

    email_send.title = "title" email_send.dispatch()

    У рассмотренного правила есть и некоторые исключения:

    • Создание функции main() , которую вызовут в главной точке входа приложения — это хороший повод нарушить это правило.
    • Использование @property для того, чтобы обращаться с методом класса как с атрибутом, тоже допустимо.
    Имена переменных и констант должны быть существительными

    Имена переменных и констант всегда должны быть существительными и никогда — глаголами (это позволяет чётко отделить их от функций).

    Вот примеры удачных имён:

    plane = Plane() customer_id = 5 KEY_COMPARISON = "abc"

    Вот — неудачные имена:

    fly = Plane() get_customer_id = 5 COMPARE_KEY = "abc"

    А если переменная или константа представляют собой список или коллекцию — им подойдёт имя, представленное существительным во множественном числе:

    planes: list[Plane] = [Plane()] # Даже если содержит всего один элемент customer_ids: set[int] = KEY_MAP: dict[str, str] = # Имена словарей остаются существительными в единственном числе
    Имена классов должны говорить сами за себя, но использование суффиксов — это нормально

    Отдавайте предпочтение именам классов, понятным без дополнительных пояснений. При этом можно использовать и суффиксы, вроде Service , Strategy , Middleware , но — только в крайнем случае, когда они необходимы для чёткого описания цели существования класса.

    Всегда давайте классам имена в единственном, а не во множественном числе. Имена во множественном числе напоминают имена коллекций элементов (например — если я вижу имя orders , то я полагаю, что это — список или итерируемый объект). Поэтому, выбирая имя класса, напоминайте себе, что после создания экземпляра класса в нашем распоряжении оказывается единственный объект.

    Классы представляют собой некие сущности

    Классы, представляющие нечто из бизнес-среды, должны называться в соответствии с названиями связанных с ними сущностей (и имена должны быть существительными!). Например — Order , Sale , Store , Restaurant и так далее.

    Пример использования суффиксов

    Представим, что надо создать класс, ответственный за отправку электронных писем. Если назвать его просто Email , цель его существования будет неясна.

    Кто-то может решить, что он может олицетворять некую сущность:

    email = Email() # Предполагаемый пример использования email.title = "Title" email.body = create_body() email.send_to = "guilatrova.dev" send_email(email)

    Такой класс следует назвать EmailSender или EmailService .

    Соглашения по именованию сущностей

    Следуйте этим соглашениям по именованию сущностей:

    Тип

    Общедоступный

    Внутренний

    Правила оформления Python-кода

    Рекомендуется использовать 4 пробела на каждый уровень отступа. Python 3 запрещает смешивание табуляции и пробелов в отступах. Код, в котором используются и те, и другие типы отступов, должен быть исправлен так, чтобы отступы в нем были расставлены только с помощью пробелов.

     def no_tab_using(): no_tab = 'Using 4 spaces' 
     def use_tab(): one_tab_using = 'Ugly' 

    2. Точки с запятой

    Не разделяйте ваши строки с помощью точек с запятой и не используйте точки с запятой для разделения команд, находящихся на одной строке.

     a = 'String' b = 15 c = 7.2 
     a = 'String'; b = 15; c = 7.2; 

    3. Скобки

    Используйте скобки экономно. Не используйте их с выражением return или с условной конструкцией, если не требуется организовать перенос строки. Однако скобки хорошо использовать для создания кортежей.

     if budget < 0: return False # ------------------- while counter  
     if (budget < 0): return (False) # ------------------- if not(line): continue # ------------------- return (result) 

    4. Пробелы в выражениях и инструкциях

    4.1 Пробелы и скобки

    4.1.1 Не ставьте пробелы внутри каких-либо скобок (обычных, фигурных и квадратных).

     pineapple(pine[1], ) 
     pineapple( pine[ 1 ], < apple: 2 >) 

    4.1.2 Никаких пробелов перед открывающей скобкой, которая начинает список аргументов, индекс или срез.

     get_number_of_guests(1) 
     get_number_of_guests (1) 
     dish['ingredients'] = cook_book[:3] 
     dish ['ingredients'] = cook_book [:3] 

    4.2 Пробелы рядом с запятой, точкой с запятой и точкой

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

     if number_of_goods == 4: print(number_of_goods, total_price) 
     if number_of_goods == 4 : print(number_of_goods , total_price) 

    4.3 Пробелы вокруг бинарных операторов

    4.3.1 Окружайте бинарные операторы одиночными пробелами с каждой стороны. Это касается присваивания ( = ), операторов сравнения ( == , , > , != , <> , , >= , in , not in , is , is not ), и булевых операторов ( and , or , not ). Используйте, как вам покажется правильным, окружение пробелами по отношению к арифметическим операторам, но расстановка пробелов по обеим сторонам бинарного оператора придает целостность коду.

     counter == 1 
     counter  

    4.3.2 Не используйте более одного пробела вокруг оператора присваивания (или любого другого оператора) для того, чтобы выровнять его с другим.

     price = 1000 price_with_taxes = 1200 price_with_taxes_and_discounts = 1100 
     price = 1000 price_with_taxes = 1200 price_with_taxes_and_discounts = 1100 

    4.3.3 Не используйте пробелы по сторонам знака = , когда вы используете его, чтобы указать на именованный аргумент или значение по умолчанию.

     def complex(real, imag=0.0): return magic(r=real, i=imag) 
     def complex(real, imag = 0.0): return magic(r = real, i = imag) 

    5. Длина строк

    Ограничивайте длину строк 79 символами (а длину строк документации и комментариев — 72 символами). В общем случае не используйте обратный слеш в качестве перехода на новую строку. Используйте доступное в Python явное объединение строк посредством круглых и фигурных скобок. Если необходимо, можно добавить дополнительную пару скобок вокруг выражения.

     style_object(self, width, height, color='black', design=None, emphasis=None, highlight=0) if (width == 0 and height == 0 and color == 'red' and emphasis == 'strong'): 

    Если ваш текст не помещается в одну строку, используйте скобки для явного объединения строк.

     long_string = ('This will build a very long long ' 'long long long long long long string') 

    Что касается длинных URL в комментариях, то располагайте их, если это необходимо, на одной строке.

     # See details at # http://www.example.com/example/example/example/example/example/example/example_example.html 
     # See details at # http://www.example.com/example/example/example/example/example/\ # example/example_example.html 

    Обратный слеш иногда используется. Например, с длинной конструкцией 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()) 

    Ещё один подобный случай — длинные assert .

    6. Пустые строки

    Отделяйте функции (верхнего уровня, не функции внутри функций) и определения классов двумя пустыми строками. Определения методов внутри класса отделяйте одной пустой строкой. Две пустые строки должны быть между объявлениями верхнего уровня, будь это класс или функция. Одна пустая строка должна быть между определениями методов и между объявлением класса и его первым методом.

     import os . . class MyClass: . def __init__(self): self.name = 'My name' . def f(self): return 'hello world' . . def MyFunc(): i = 12345 return i . myclass = MyClass() 

    Используйте (без энтузиазма) пустые строки в коде функций, чтобы отделить друг от друга логические части.

    Python расценивает символ control+L как незначащий (whitespace), и вы можете использовать его, потому что многие редакторы обрабатывают его как разрыв страницы — таким образом, логические части в файле будут на разных страницах. Однако не все редакторы распознают control+L и могут на его месте отображать другой символ.

    7. Имена

    Имена, которых следует избегать:

      Односимвольные имена, исключая счетчики либо итераторы. Никогда не используйте символы l (маленькая латинская буква «эль»), O (заглавная латинская буква «о») или I (заглавная латинская буква «ай») как однобуквенные идентификаторы. В некоторых шрифтах эти символы неотличимы от цифры один и нуля. Если очень нужно l , пишите вместо неё заглавную L . Хорошо

     long_name = 'Хорошее имя переменной' L = 'Допустимо, но лучше избегать' 
     l = 1 I = 1 O = 0 
     import my_module 
     import my-module 
     my_variable = 'Variable' 
     __myvariable__ = 'Variable' 

    7.1 Имена функций

    Имена функций должны состоять из маленьких букв, а слова разделяться символами подчеркивания — это необходимо, чтобы увеличить читабельность.

     my_variable = 'Variable' 
     My-Variable = 'Variable' 

    Стиль mixedCase допускается в тех местах, где уже преобладает такой стиль — для сохранения обратной совместимости.

    7.2 Имена модулей и пакетов

    Модули должны иметь короткие имена, состоящие из маленьких букв. Можно использовать символы подчёркивания, если это улучшает читабельность. То же самое относится и к именам пакетов, однако в именах пакетов не рекомендуется использовать символ подчёркивания.

    Так как имена модулей отображаются в имена файлов, а некоторые файловые системы являются нечувствительными к регистру символов и обрезают длинные имена, очень важно использовать достаточно короткие имена модулей — это не проблема в Unix, но, возможно, код окажется непереносимым в старые версии Windows, Mac, или DOS.

     import vkapi 
     import My-First-VKontakte-API-Modul 

    7.3 Имена классов

    Все имена классов должны следовать соглашению CapWords почти без исключений.

     class MyFirstClass: 

    Иногда вместо этого могут использоваться соглашения для именования функций, если интерфейс документирован и используется в основном как функции.

    Обратите внимание, что существуют отдельных соглашения о встроенных именах: большинство встроенных имен — одно слово (либо два слитно написанных слова), а соглашение CapWords используется только для именования исключений и встроенных констант.

    Так как исключения являются классами, к исключениями применяется стиль именования классов. Однако вы можете добавить Error в конце имени (если, конечно, исключение действительно является ошибкой).

    7.4 Имена констант

    Константы обычно объявляются на уровне модуля и записываются только заглавными буквами, а слова разделяются символами подчеркивания.

     MAX_OVERFLOW = 10 TOTAL = 100 

    8. Комментарии

    Комментарии, противоречащие коду, хуже, чем отсутствие комментариев. Всегда исправляйте комментарии, если меняете код!

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

    Ставьте два пробела после точки в конце предложения.

    Если вы — программист, не говорящий по-английски, то всё равно следует использовать английский язык для написания комментариев. Особенно, если нет уверенности на 120% в том, что этот код будут читать только люди, говорящие на вашем родном языке.

    8.1 Блоки комментариев

    Блок комментариев обычно объясняет код (весь или только некоторую часть), идущий после блока, и должен иметь тот же отступ, что и сам код. Каждая строчка такого блока должна начинаться с символа # и одного пробела после него (если только сам текст комментария не имеет отступа).

    Абзацы внутри блока комментариев разделяются строкой, состоящей из одного символа # .

    8.2 Комментарии в строке с кодом

    Старайтесь реже использовать подобные комментарии.

    Такой комментарий находится в той же строке, что и инструкция. «Встрочные» комментарии должны отделяться хотя бы двумя пробелами от инструкции. Они должны начинаться с символа # и одного пробела.

    Комментарии в строке с кодом не нужны и только отвлекают от чтения, если они объясняют очевидное.

     counter = counter + 1 # Increment counter 

    8.3 Строки документации

    Соглашения о написании хорошей документации (docstrings) зафиксированы в PEP 257.

    Пишите документацию для всех публичных модулей, функций, классов, методов. Строки документации необязательны для приватных методов, но лучше написать, что делает метод. Комментарий нужно писать после строки с def .

    Очень важно, чтобы закрывающие кавычки стояли на отдельной строке. А еще лучше, если перед ними будет ещё и пустая строка.

     """Return something useful Optional plotz says to frobnicate the bizbaz first. """ 

    Для однострочной документации можно оставить """ на той же строке.

    9. Циклы

    9.1 Циклы по спискам

    Если нам необходимо в цикле пройти по всем элементам списка, то хорошим тоном (да и более читаемым) будет такой способ:

     colors = ['red', 'green', 'blue', 'yellow'] for color in colors: print(color) 

    И хотя бывалые программисты или просто любители C могут использовать и такой код, это моветон.

     colors = ['red', 'green', 'blue', 'yellow'] for i in range(len(colors)): print(colors[i]) 

    А если нужно пройти по списку задом наперед, то лучше всего использовать метод reversed:

     colors = ['red', 'green', 'blue', 'yellow'] for color in reversed(colors): print(color) 

    Вместо того чтобы писать избыточный код, который и читается-то не очень внятно.

     colors = ['red', 'green', 'blue', 'yellow'] for i in range(len(colors)-1, -1, -1): print(colors[i]) 

    9.2 Циклы по списку чисел

    Если есть необходимость пройти в цикле по ряду чисел, то метод range будет намного приемлемее, как минимум потому, что этот метод потребляет намного меньше памяти, чем вариант в блоке "Плохо". А представьте, что у вас ряд из трёх миллиардов последовательных чисел!

     for i in range(6): print(i**2) 
     for i in [0, 1, 2, 3, 4, 5]: print(i**2) 

    9.3 Циклы по спискам с индексами

    Метод enumerate позволяет получить сразу индекс и значение из списка, что, во-первых, предоставляет множество возможностей для дальшнейшего проектирования, а во-вторых, такой код легче читается и воспринимается.

     colors = ['red', 'green', 'blue', 'yellow'] for i, color in enumerate(colors): print(i, '-->', color) 
     colors = ['red', 'green', 'blue', 'yellow'] for i in range(len(colors)): print(i, '-->', colors[i]) 

    9.4 Циклы по двум спискам

    Используя метод zip, мы получаем из двух списков один список кортежей, что более удобно для дальнейшего использования и требует меньше памяти. Да и просто этот вариант более элегантный.

     names = ['raymond', 'rachel', 'matthew'] colors = ['red', 'green', 'blue', 'yellow'] for name, color in zip(names, colors): print(name, '-->', color) 
     names = ['raymond', 'rachel', 'matthew'] colors = ['red', 'green', 'blue', 'yellow'] n = min(len(names), len(colors)) for i in range(n): print(names[i], '-->', colors[i]) 

    10. Импорты

    Каждый импорт, как правило, должен быть на отдельной строке.

     import os import sys 
     import sys, os 

    В то же время, можно писать так:

     from subprocess import Popen, PIPE 

    Импорты всегда располагаются в начале файла, сразу после комментариев уровня модуля, строк документации, перед объявлением констант и объектов уровня модуля. Импорты должны быть сгруппированы в порядке от самых простых до самых сложных:

    • импорты из стандартной библиотеки,
    • сторонние импорты,
    • импорты из библиотек вашего приложения.

    Наряду с группированием, импорты должны быть отсортированы лексикографически, нерегистрозависимо, согласно полному пути до каждого модуля.

     import foo from foo import bar from foo.bar import baz from foo.bar import Quux from Foob import ar 

    Рекомендуется абсолютное импортирование, так как оно обычно более читаемо и ведет себя лучше (или, по крайней мере, даёт понятные сообщения об ошибках), если импортируемая система настроена неправильно (например, когда каталог внутри пакета заканчивается на sys.path ).

     import mypkg.sibling from mypkg import sibling from mypkg.sibling import example 

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

     from . import sibling from .sibling import example 

    Следует избегать шаблонов импортов ( from import * ), так как они делают неясным то, какие имена присутствуют в глобальном пространстве имён, что вводит в заблуждение как читателей, так и многие автоматизированные средства.

    Рекомендуем также ознакомиться с полной версией соглашения о том, как писать код на Python (PEP 8)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *