Субота, 28 Травня, 2022
--- Advertisement ---

ДодомуПрограмуванняPEP 8 - посібник з написання коду на Python
--- Advertisement ---

PEP 8 – посібник з написання коду на Python

PEP 8 - посібник з написання коду на Python

Зовнішній вигляд коду

Цей документ описує угоду про те, як писати код для python, включаючи стандартну бібліотеку, що входить до складу python.

PEP 8 створено на основі рекомендацій Гуідо ван Россума з додаваннями Баррі. Якщо десь виник конфлікт, ми обирали стиль Гуїдо. І, звичайно, цей PEP може бути неповним (фактично він, напевно, ніколи не буде закінчений).

Ключова ідея Гуїдо така: код читається набагато більше, ніж пишеться. Власне, рекомендації про стиль написання коду спрямовані на те, щоб покращити читання коду та зробити його узгодженим між великою кількістю проектів. В ідеалі весь код буде написаний в єдиному стилі, і будь-який зможе легко його прочитати.

--- Advertisement ---

Це керівництво про узгодженість та єдність. Узгодженість із цим керівництвом дуже важлива. Узгодженість усередині одного проекту ще важливіша. А узгодженість усередині модуля чи функції – найважливіше. Але важливо пам’ятати, що іноді це керівництво не застосовується і розуміти, коли можна відійти від рекомендацій. Коли ви сумніваєтеся, просто подивіться інші приклади і вирішіть, який виглядає краще.

Дві причини для того, щоб порушити ці правила:

  • Коли застосування правила зробить код менш читаним навіть для того, хто звик читати код, який слідує правилам.
  • Щоб писати в єдиному стилі з кодом, який вже є в проекті і який порушує правила (можливо, з історичних причин) — це, нарешті, можливість переписати чужий код.

Тривалі рядки повинні вирівнювати обгорнуті елементи або вертикально, використовуючи неявну лінію у дужках (круглих, квадратних або фігурних), або з використанням висячого відступу. При використанні висячого відступу слід застосовувати такі міркування: перша лінія має бути з аргументами, інші рядки повинні чітко сприйматися як продовження лінії.

Правильно:

#вирівняно по роздільнику, що відкриває
foo = long_function_name(var_one, var_two,
                         var_three, var_four)
                         
#більше відступів включено для відхилення його від інших
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)


Неправильно:

#Більше відступів потрібно, щоб відрізнити його від інших
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)

Опціонально:

#Немає потреби у більшій кількості відступів.
foo = long_function_name(
  var_one, var_two,
  var_three, var_four)
Круглі/квадратні/фігурні дужки, що закривають, у багаторядкових конструкціях можуть знаходитися під першим непробільним символом останнього рядка списку, наприклад:
my_list = [
    1, 2, 3,
    4, 5, 6,
    ]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )
або бути під першим символом рядка, що починає багаторядкову конструкцію:
my_list = [
    1, 2, 3,
    4, 5, 6,
]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

Табуляція чи прогалини?

Прогалини – найкращий метод відступів.

Табуляція повинна використовуватися лише для підтримки коду, написаного з відступами табуляцією.

Python 3 забороняє змішування табуляції та пробілів у відступах.

Python 2 намагається перетворити табуляцію на прогалини.

Коли ви викликаєте інтерпретатор Python 2 у командному рядку з параметром -t, він видає попередження (warnings) при використанні змішаного стилю у відступах, а запустивши інтерпретатор з параметром -tt ви отримаєте в цих місцях помилки (errors). Ці настройки дуже рекомендуються!

Максимальна довжина рядка

Обмежте довжину рядка максимум 79 символами.

Для більш довгих блоків тексту з меншими структурними обмеженнями (рядки документації або коментарі) довжину рядка слід обмежити 72 символами.

Обмеження необхідної ширини вікна редактора дозволяє мати кілька відкритих файлів пліч-о-пліч, і добре працює при використанні інструментів аналізу коду, які надають дві версії в сусідніх стовпцях.

Деякі команди віддають перевагу більшій довжині рядка. Для коду, що підтримується виключно або переважно цією групою, в якій можуть дійти згоди з цього питання, нормально збільшення довжини рядка з 80 до 100 символів (фактично збільшуючи максимальну довжину до 99 символів), за умови, що коментарі та рядки документації все ще будуть 72 символи.

Стандартна бібліотека Python консервативна і вимагає обмеження довжини рядка 79 символів (а рядків документації/коментарів 72).

Переважним способом перенесення довгих рядків є використання продовжень рядків Python всередині круглих, квадратних і фігурних дужок. Довгі рядки можуть бути розбиті на кілька рядків, загорнуті в дужки. Це краще використання зворотної косої межі для продовження рядка.

Зворотна коса досі може бути використана іноді. Наприклад, довга конструкція 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.

Зробіть правильні відступи для перенесеного рядка. Переважно вставити перенос рядка після логічного оператора, але не перед ним. Наприклад:

class Rectangle(Blob):

    def __init__(self, width, height,
                 color='black', emphasis=None, highlight=0):
        if (width == 0 and height == 0 and
                color == 'red' and emphasis == 'strong' or
                highlight > 100):
            raise ValueError("sorry, you lose")
        if width == 0 and height == 0 and (color == 'red' or
                                           emphasis is None):
            raise ValueError("I don't think so -- values are %s, %s" %
                             (width, height))
        Blob.__init__(self, width, height,
                      color, emphasis, highlight)

Порожні рядки

Відокремлюйте функції верхнього рівня та визначення класів двома порожніми рядками.

Визначення методів усередині класу поділяються одним порожнім рядком.

Додаткові порожні рядки можна використовувати для розділення різних груп подібних функцій. Порожні рядки можуть бути опущені між кількома пов’язаними однорядками (наприклад, набір фіктивних реалізацій).

Використовуйте порожні рядки у функціях, щоб вказати логічні розділи.

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

Кодування вихідного файлу

Кодування Python має бути UTF-8 (ASCII у Python 2).

Файли ASCII (Python 2) або UTF-8 (Python 3) не повинні мати оголошення кодування.

У стандартній бібліотеці, нестандартні кодування повинні використовуватися тільки для цілей тестування, або коли коментар або рядок документації вимагає згадати ім’я автора, що містить ASCII символи; в інших випадках використання \x, \u, \U або \N – найкращий спосіб включити не ASCII символи в рядкових літералах.

Починаючи з версії python 3.0 у стандартній бібліотеці діє така угода: усі ідентифікатори зобов’язані містити лише ASCII символи, та означати англійські слова скрізь, де це можливо (у багатьох випадках використовуються скорочення чи неанглійські технічні терміни). Крім того, рядки та коментарі теж повинні містити лише ASCII символи. Винятки становлять: (а) test case, що тестує не-ASCII особливості програми, та (б) імена авторів. Автори, чиї імена засновані не на латинському алфавіті, повинні транслітерувати свої імена до латиниці.

Проекти з відкритим кодом для широкої аудиторії також рекомендують використовувати цю угоду.

Імпорти

  • Кожен імпорт, як правило, має бути на окремому рядку.

Правильно:

import os
import sys

Неправильно:

import sys, os

У той же час можна писати так:

from subprocess import Popen, PIPE
  • Імпорти завжди розміщуються на початку файлу, відразу після коментарів до модуля та рядків документації, і перед оголошенням констант.

Імпорти мають бути згруповані у такому порядку:

  1. імпорти зі стандартної бібліотеки
  2. імпорти сторонніх бібліотек
  3. імпорти модулів поточного проекту

Вставляйте порожній рядок між групою імпорту.

Вказуйте специфікації all після імпорту.

  • Рекомендується абсолютне імпортування, так як воно зазвичай більш читане і поводиться краще (або принаймні дає зрозумілі повідомлення про помилки) якщо імпортована система налаштована неправильно (наприклад, коли каталог всередині пакета закінчується на sys.path):
import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example

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

from . import sibling
from .sibling import example

У стандартній бібліотеці слід уникати складної структури пакетів і завжди використовувати абсолютні імпорти.

Неявні імпорти ніколи не повинні бути використані, і були видалені в Python 3.

  • Коли ви імпортуєте клас із модуля, можна писати так:
from myclass import MyClass
from foo.bar.yourclass import YourClass

Якщо таке написання викликає конфлікт імен, тоді пишіть:

import myclass
import foo.bar.yourclass

І використовуйте “myclass.MyClass” та “foo.bar.yourclass.YourClass”.

  • Шаблони імпортів (from import *) слід уникати, оскільки вони роблять незрозумілим те, які імена присутні у глобальному просторі імен, що вводить в оману як читачів, і багато автоматизованих коштів. Існує один виправданий приклад використання шаблону імпорту, який полягає в опублікуванні внутрішнього інтерфейсу як частина громадського API (наприклад, переписавши реалізацію на чистому Python у модулі акселератора (і не буде відомо, які саме функції будуть перезаписані).

Прогалини у виразах та інструкціях

Уникайте використання прогалин у таких ситуаціях:

  • Безпосередньо всередині круглих, квадратних чи фігурних дужок.

Правильно:

spam(ham[1], {eggs: 2})

Неправильно:

spam( ham[ 1 ], { eggs: 2 } )
  • Безпосередньо перед комою, точкою з комою або двокрапкою:

Правильно:

f x == 4: print(x, y); x, y = y, x

Неправильно:

if x == 4 : print(x, y); x , y = y , x
  • Відразу перед дужкою, після якої починається список аргументів при виклику функції:

Правильно:

spam(1)

Неправильно:

spam (1)
  • Відразу перед дужкою, після якої дотримується індекс або зріз:

Правильно:

dict['key'] = list[index]

Неправильно:

dict ['key'] = list [index]
  • Використання більше одного пробілу навколо оператора присвоєння (або будь-якого іншого) для того, щоб вирівняти його з іншим:

Правильно:

x = 1
y = 2
long_variable = 3

Неправильно:

x             = 1
y             = 2
long_variable = 3

Інші рекомендації

Завжди оточуйте ці бінарні оператори одним пропуском з кожної сторони: привласнення (=, +=, -= та інші), порівняння (==, <, >, !=, <>, <=, >=, in, not in, is, is not), логічні (and, or, not).

Якщо використовуються оператори з різними пріоритетами, спробуйте додати пробіли навколо операторів із найнижчим пріоритетом. Використовуйте свої власні судження, проте ніколи не використовуйте більше одного пробілу, і завжди використовуйте однакову кількість пробілів по обидва боки бінарного оператора.

Правильно:

i = i + 1
submitted += 1
x = x * 2 - 1
hypot2 = x * x + y * y
c = (a+b) * (a-b)

Неправильно:

i=i+1
submitted +=1
x = x * 2 - 1
hypot2 = x * x + y * y
c = (a + b) * (a - b)
  • Не використовуйте пробіли навколо знака =, якщо він використовується для позначення іменованого аргументу або параметрів за замовчуванням.

Правильно:

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

Неправильно:

def complex(real, imag = 0.0):
    return magic(r = real, i = imag)
  • Не використовуйте складові вказівки (кілька команд в одному рядку).

Правильно:

if foo == 'blah':
do_blah_thing()
do_one()
do_two()
do_three()

Неправильно:

if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three()
  • Іноді можна писати тіло циклів while, for або гілку if у тому рядку, якщо команда коротка, але якщо команд кілька, ніколи так не пишіть. А також уникайте довгих рядків!

Точно неправильно:

if foo == 'blah': do_blah_thing()
for x in lst: total + = x
while t < 10: t = delay()

Ймовірно, неправильно:

if foo == 'blah': do_blah_thing()
else: do_non_blah_thing()

try: something()
finally: cleanup()

do_one(); do_two(); do_three(long, argument,
                             list, like, this)

if foo == 'blah': one(); two(); three()

Коментарі

Коментарі, що суперечать коду, гірші, ніж відсутність коментарів. Завжди виправляйте коментарі, якщо ви змінюєте код!

Коментарі мають бути закінченими пропозиціями. Якщо коментар – фраза або речення, перше слово має бути написано з великої літери, якщо це не ім’я змінної, яка починається з маленької літери (ніколи не змінюйте регістр змінної!).

Якщо коментар короткий, можна опустити крапку наприкінці речення. Блок коментарів зазвичай складається з одного або більше абзаців, складених із повноцінних речень, тому кожна пропозиція має закінчуватися точкою.

Ставте два пробіли після точки наприкінці пропозиції.

Програмісти, які не говорять англійською мовою, будь ласка, пишіть коментарі англійською, якщо ви не впевнені на 120%, що ваш код ніколи не будуть читати люди, які не знають вашої рідної мови.

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

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

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

“Зустрічні” коментарі

Намагайтеся рідше використовувати такі коментарі.

Такий коментар знаходиться в тому ж рядку, що й інструкція. “Зустрічні” коментарі повинні відокремлюватися принаймні двома пробілами від інструкції. Вони повинні починатися з символу # та одного пробілу.

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

x = x + 1 # Increment x

Втім, такі коментарі іноді корисні:

x = x + 1 # Компенсація кордону

Рядки документації

  • Пишіть документацію для всіх публічних модулів, функцій, класів, методів. Рядки документації не є обов’язковими для приватних методів, але краще написати, що робить метод. Коментар слід писати після рядка з def.
  • PEP 257 пояснює, як правильно та добре документувати. Зауважте, дуже важливо, щоб лапки, що закривають, стояли на окремому рядку. А ще краще, якщо перед ними буде ще й порожній рядок, наприклад:
"""Return a foobang
Optional plotz says to frobnicate bizbaz first.
"""
  • Для однорядкової документації можна залишити лапки на тому ж рядку.

Контроль версій

Якщо вам потрібно використовувати Subversion, CVS або RCS у ваших вихідних кодах, робіть так:

__version__ = "$Revision: 1a40d4eaa00b $"
# $Source$

Вставляйте ці рядки після документації модуля перед будь-яким іншим кодом та відокремлюйте їх порожніми рядками по одному до та після.

Угоди за назвою

Угоди за іменуванням змінних у python трохи туманні, тому їх список ніколи не буде повним – проте нижче ми наводимо список рекомендацій, що діють на даний момент. Нові модулі та пакети повинні бути написані згідно з цими стандартами, але якщо в будь-якій вже існуючій бібліотеці ці правила порушуються, краще писати в єдиному з нею стилі.

Головний принцип

Імена, які можна побачити користувачеві як частину громадського API, повинні дотримуватися конвенцій, які відображають використання, а не реалізацію.

Опис: Стилі імен

Існує багато різних стилів. Допоможемо вам розпізнати, який іменований стиль використовується, незалежно від того, для чого він використовується.

Зазвичай розрізняють такі стилі:

  • b (одинакова маленька літера)
  • B (одиночна велика літера)
  • lowercase (слово в нижньому регістрі)
  • lower_case_with_underscores (слова з маленьких букв із підкресленнями)
  • UPPERCASE (великі літери)
  • UPPERCASE_WITH_UNDERSCORES (слова із великих літер із підкресленнями)
  • CapitalizedWords (слова з великими літерами, або CapWords, або CamelCase). Примітка: коли ви використовуєте абревіатури в такому стилі, пишіть усі літери абревіатури великими – HTTPServerError краще, ніж HttpServerError.
  • mixedCase (відрізняється від CapitalizedWords тим, що перше слово починається з маленької літери)
  • Capitalized_Words_With_Underscores (слова з великими літерами та підкресленнями – потворно!)

Ще існує стиль, у якому імена, що належать до однієї логічної групи, мають один короткий префікс. Цей стиль рідко використовується в Python, але ми згадуємо його для повноти. Наприклад, функція os.stat() повертає кортеж, імена в якому традиційно мають вигляд st_mode, st_size, st_mtime і таке інше. (Так зроблено, щоб підкреслити відповідність цих полів структурі системних викликів POSIX, що допомагає знайомим із нею програмістам).

У бібліотеці X11 використовується префікс Х для всіх public-функцій. У python цей стиль вважається зайвим, тому що перед полями та іменами методів стоїть ім’я об’єкта, а перед іменами функцій стоїть ім’я модуля.

На додаток, використовуються такі спеціальні форми запису імен з додаванням символу підкреслення на початок або кінець імені:

  • _single_leading_underscore: слабкий індикатор того, що ім’я використовується для внутрішніх потреб. Наприклад, від M import * не буде імпортувати об’єкти, чиї імена починаються з символу підкреслення.
  • single_trailing_underscore_: використовується за згодою для уникнення конфліктів з ключовими словами мови python, наприклад:
Tkinter.Toplevel(master, class_='ClassName')
  • __double_leading_underscore: змінює ім’я атрибута класу, тобто в класі FooBar поле __boo стає _FooBar__boo.
  • double_leading_and_trailing_underscore (подвійне підкреслення на початку та наприкінці імені): магічні методи або атрибути, що знаходяться в просторах імен, керованих користувачем. Наприклад, init, import або file. Не вигадуйте такі імена, використовуйте їх тільки так, як написано у документації.

Приписи: угоди на ім’я

Імена, яких слід уникати

Ніколи не використовуйте символи l (маленька латинська літера «ель»), O (заголовна латинська літера «о») або I (заголовна латинська літера «ай») як однолітерні ідентифікатори.

У деяких шрифтах ці символи не відрізняються від цифри один і нуля. Якщо дуже потрібно l, пишіть замість неї велику L.

Імена модулів та пакетів

Модулі повинні мати короткі імена, що складаються з невеликих літер. Можна використовувати символи підкреслення, якщо це покращує читабельність. Те ж саме стосується і до імен пакетів, однак у іменах пакетів не рекомендується використовувати символ підкреслення.

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

Коли модуль розширення, написаний С або C++, має супутній python-модуль (що містить інтерфейс високого рівня), С/С++ модуль починається з символу підкреслення, наприклад, _socket.

Імена класів

Імена класів повинні зазвичай виконувати угоду CapWords.

Натомість можуть використовуватися угоди для іменування функцій, якщо інтерфейс документований і використовується в основному як функції.

Зверніть увагу, що існують окремі угоди про вбудовані імена: більшість вбудованих імен – одне слово (або два разом написані слова), а угода CapWords використовується тільки для іменування винятків і вбудованих констант.

Імена винятків

Оскільки винятки є класами, до винятків застосовується іменування класів. Однак, ви можете додати Error в кінці імені (якщо, звичайно, виняток дійсно є помилкою).

Імена глобальних змінних

Сподіватимемося, що глобальні змінні використовуються лише всередині одного модуля. Керуйтеся тими самими угодами, що й для імен функцій.

Додайте в модулі, які написані так, щоб їх використовували за допомогою M import *, механізм all, щоб запобігти експорту глобальних змінних. Або, використовуйте стару угоду, додаючи перед іменами таких глобальних змінних один символ підкреслення (яким ви можете позначити ті глобальні змінні, які використовуються лише всередині модуля).

Імена функцій

Імена функцій повинні складатися з маленьких літер, а слова розділятися символами підкреслення – це необхідно, щоб збільшити читабельність.

Стиль mixedCase допускається у тих місцях, де вже переважає такий стиль, для збереження зворотної сумісності.

Аргументи функцій та методів

Завжди використовуйте self як перший аргумент методу екземпляра об’єкта.

Завжди використовуйте cls як перший аргумент методу класу.

Якщо ім’я аргументу конфліктує із зарезервованим ключовим словом python, зазвичай краще додати до кінця імені символ підкреслення, ніж спотворити написання слова або використовувати абревіатуру. Таким чином, class_ краще, ніж clss. (Можливо, добрим варіантом буде підібрати синонім).

Імена методів та змінних екземплярів класів

Використовуйте той самий стиль, що й для імен функцій: імена повинні складатися з маленьких літер, а слова розділятимуться символами підкреслення.

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

Щоб уникнути конфліктів імен із підкласами, використовуйте два провідні підкреслення.

Python спотворює ці імена: якщо клас Foo має атрибут з ім’ям __a, він не може бути доступним як Foo.__a. (Наполегливий користувач все ще може отримати доступ, викликавши Foo._Foo__a.) Взагалі, два провідних підкреслення повинні використовуватися тільки для того, щоб уникнути конфліктів імен з атрибутами класів, призначених для успадкування.

Примітка: є деякі розбіжності щодо використання __ імена (див. нижче).

Константи

Константи зазвичай оголошуються лише на рівні модуля і записуються лише великими літерами, а слова поділяються символами підкреслення. Наприклад: MAX_OVERFLOW, TOTAL.

Проектування наслідування

Обов’язково вирішіть, яким має бути метод класу або екземпляра класу (далі – атрибут) – публічний чи непублічний. Якщо ви маєте сумнів, виберіть непублічний атрибут. Потім простіше зробити його публічним, ніж навпаки.

Публічні атрибути – це ті, які будуть використовувати інші програмісти, і ви повинні бути впевнені у відсутності зворотної несумісності. Непублічні атрибути, у свою чергу, не призначені для використання третіми особами, тому ви можете не гарантувати, що не зміните або видаліть їх.

Ми не використовуємо термін “приватний атрибут”, тому що насправді в python таких не буває.

Інший тип атрибутів класів належить так званому підкласам API (в інших мовах вони часто називаються protected). Деякі класи проектуються так щоб успадковували інші класи, які розширюють чи модифікують поведінка базового класу. Коли ви проектуєте такий клас, вирішіть і явно вкажіть, які атрибути є публічними, які належать підкласам API, а які використовуються тільки базовим класом.

Тепер сформулюємо рекомендації:

  • Відкриті атрибути не повинні мати на початку імені символу підкреслення.
  • Якщо ім’я відкритого атрибута конфліктує з ключовим словом мови, додайте до кінця імені один символ підкреслення. Це більш переважно, ніж абревіатура або спотворення написання (проте, у цього правила є виняток – аргумент, який означає клас, особливо перший аргумент методу класу (class method) повинен мати ім’я cls).
  • Назвіть прості публічні атрибути зрозумілими іменами і не пишіть складні методи доступу та зміни (accessor/mutator, get/set, прим. перекл.) Пам’ятайте, що в python дуже легко додати їх потім, якщо потрібно. У цьому випадку використовуйте властивості (properties), щоб приховати функціональну реалізацію синтаксисом доступу до атрибутів.

Примітка 1: Властивості працюють тільки в класах нового стилю (в Python 3 всі класи є такими).

Примітка 2: Постарайтеся позбавитися побічних ефектів, пов’язаних із функціональною поведінкою; втім, такі речі, як кешування цілком допустимі.

Примітка 3: Уникайте використання обчислювально-затратних операцій, тому що через запис за допомогою атрибутів створюється враження, що доступ відбувається (відносно) швидко.

  • Якщо ви плануєте клас таким чином, щоб від нього успадковувалися інші класи, але не хочете, щоб підкласи успадкували деякі атрибути, додайте в імена два символи підкреслення на початок, і жодного в кінець. Механізм зміни імен у python спрацює так, що ім’я класу додасться до імені такого атрибуту, що дозволить уникнути конфлікту імен із атрибутами підкласів.

Примітка 1: Будьте уважні: якщо підклас матиме те саме ім’я класу та ім’я атрибута, то знову виникне конфлікт імен.

Примітка 2: Механізм зміни імен може ускладнити налагодження або роботу з getattr(), однак він добре документований та легко реалізується вручну.

Примітка 3: Не всім подобається цей механізм, тому намагайтеся досягти компромісу між необхідністю уникнути конфлікту імен та можливістю доступу до цих атрибутів.

Загальні рекомендації

  • Код має бути написаний так, щоб не залежати від різних реалізацій мови (PyPy, Jython, IronPython, Pyrex, Psyco та ін.).
    Наприклад, не покладайтеся на ефективну реалізацію в CPython конкатенації рядків у виразах типу a+=b або a=a+b. Такі інструкції виконуються значно повільніше у Jython. У критичних часах виконання частин програми використовуйте ”.join() — таким чином склеювання рядків буде виконано за лінійний час незалежно від реалізації python.
  • Порівняння з None повинні обов’язково виконуватись з використанням операторів is або is not, а не за допомогою операторів порівняння. Крім того, не пишіть if x, якщо маєте на увазі if x is not None – якщо, наприклад, при тестуванні така змінна може прийняти значення іншого типу, відмінного від None, але при наведенні типів може вийти False!
  • При реалізації методів порівняння найкраще реалізувати всі 6 операцій порівняння (eq, ne, lt, le, gt, ge), ніж покладатися на те, що інші програмісти будуть використовувати тільки конкретний вид порівняння.

Для мінімізації зусиль можна скористатися декоратором functools.total_ordering() для реалізації методів.

PEP 207 показує, що інтерпретатор може змінити y > х на х < y, y >= х на х <= y, і може поміняти місцями аргументи х == y і х! = y. Гарантується, що операції sort() та min() використовують оператор <, а max() використовує оператор >. Однак, найкраще здійснити усі шість операцій, щоб не виникало плутанини в інших місцях.

  • Завжди використовуйте вираз def, а не привласнення лямбда-виразу до імені.

Правильно:

def f(x): return 2*x

Неправильно:

f = lambda x: 2*x
  • Наслідуйте свій клас виключення від Exception, а не від BaseException. Пряме успадкування від BaseException зарезервовано для винятків, які слід перехоплювати.
  • Використовуйте ланцюжки винятків відповідним чином. У Python 3 “raise X from Y” слід використовувати для вказівки явної заміни без втрати налагоджувальної інформації.
    Коли навмисно замінюється виняток (використання “raise X” у Python 2 або “raise X from None” у Python 3.3+), простежте, щоб відповідна інформація передалася в новий виняток (такі, як збереження імені атрибута при перетворенні KeyError в AttributeError або вкладення тексту вихідного виключення у новому).
  • Коли ви генеруєте виняток, пишіть raise ValueError(‘message’) замість старого синтаксису raise ValueError, message.
    Стара форма запису заборонена у python 3.
    Таке використання краще, тому що через дужки не потрібно використовувати символи для продовження перенесених рядків, якщо ці рядки довгі або якщо використовується форматування.
  • Коли код перехоплює винятки, перехоплюйте конкретні помилки, замість простого виразу except:.

Наприклад, пишіть ось так:

try:
    import platform_specific_module
except ImportError:
    platform_specific_module = None

Просте написання “except:” також перехопить і SystemExit, і KeyboardInterrupt, що породить проблеми, наприклад, складніше завершити програму натисканням control+C. Якщо ви дійсно маєте намір перехопити всі винятки, пишіть “except Exception:”.

Хорошим правилом є обмеження використання “except:”, крім двох випадків:

  1. Якщо обробчик виводить користувачеві все про помилку; принаймні користувач знатиме, що сталася помилка.
  2. Якщо потрібно виконати певний код після перехоплення виключення, а потім знову “кинути” його для обробки десь в іншому місці. Зазвичай краще користуватися конструкцією “try…finally”.
  • При зв’язуванні перехоплених винятків з ім’ям, віддайте перевагу явному синтаксису прив’язки, доданому в Python 2.6:
try:
    process_data()
except Exception as exc:
    raise DataProcessingFailedError(str(exc))

Це єдиний синтаксис, що підтримується Python 3, який дозволяє уникнути проблем неоднозначності, пов’язаних з більш старим синтаксисом на основі коми.

  • При перехопленні помилок операційної системи, краще використовувати явну ієрархію винятків, введену в Python 3.3, замість аналізу значень errno.
  • Постарайтеся укладати в кожну конструкцію try…except мінімум коду, щоб легко відловлювати помилки. Знову ж таки, це дозволяє уникнути замаскованих помилок.

Правильно:

try:
    value = collection[key]
except KeyError:
    return key_not_found(key)
else:
    return handle_value(value)

Неправильно:

try:
    # Тут багато дій!
    return handle_value(collection[key])
except KeyError:
    # Тут також перехватиться KeyError, 
    # який може бути сгенерований handle_value()
    return key_not_found(key)
  • Коли ресурс є локальним на ділянці коду, використовуйте вираз with для того, щоб після виконання він був очищений оперативно та надійно.
  • Менеджери контексту слід викликати за допомогою окремої функції або методу, щоразу, коли вони роблять щось інше, ніж отримання та звільнення ресурсів.

Наприклад:

Правильно:

with conn.begin_transaction():
    do_stuff_in_transaction(conn)

Неправильно:

with conn:
    do_stuff_in_transaction(conn)

Останній приклад не дає жодної інформації, що вказує на те, що enter і exit роблять щось, крім закриття з’єднання після транзакції. Бути очевидним важливо в даному випадку.

  • Використовуйте рядкові методи замість модуля string – вони завжди швидше і мають той же API для unicode-рядків. Можна відмовитись від цього правила, якщо потрібна сумісність з версіями python молодшого 2.0.
    У Python 3 залишилися лише рядкові методи.
  • Використовуйте ”.startswith() та ”.endswith() замість обробки зрізів рядків для перевірки суфіксів або префіксів.

startswith() і endswith() виглядають чистішими і породжують менше помилок. Наприклад:

Правильно:

if foo.startswith('bar'):

Неправильно:

if foo[:3] == 'bar':

Порівняння типів об’єктів потрібно робити за допомогою isinstance(), а не прямим порівнянням типів:

Правильно:

if isinstance(obj, int):

Неправильно:

if type(obj) is type(1):

Коли ви перевіряєте, чи є об’єкт рядком, зверніть увагу на те, що рядок може бути unicode-рядком. У python 2 у str і unicode є загальний базовий клас, тому ви можете написати:

if isinstance(obj, basestring):

Зазначимо, що у Python 3, unicode і basestring більше немає (є тільки str) і bytes більше є свого роду рядком (це послідовність цілих чисел).

  • Для послідовностей (рядків, списків, кортежів) використовуйте той факт, що порожня послідовність є false:

Правильно:

if not seq:
if seq:

Неправильно:

if len(seq)
if not len(seq)
  • Не користуйтеся рядковими константами, які мають важливі прогалини в кінці – вони невидимі, а багато редакторів (а тепер і reindent.py) обрізають їх.

Не порівнюйте логічні типи з True та False за допомогою ==:

Правильно:

if greeting:

Неправильно:

if greeting == True:

Зовсім неправильно:

if greeting is True:
Дати оцінку данній статті
--- Advertisement ---

--- Advertisement ---

СХОЖІ ЗАПИСИ

НАПИСАТИ ВІДПОВІДЬ

введіть свій коментар!
введіть тут своє ім'я

--- Advertisement ---

Останні Новини