Привет, Хабр! Предлагаю вашему вниманию перевод статьи Хорошие и плохие практики кодирования на Python от Дуомли.
Python — это язык программирования высокого уровня, в котором особое внимание уделяется читабельности.
Он разрабатывается, поддерживается и часто используется в соответствии с The Zen of Python или PEP 20. В этой статье показано несколько примеров хороших и плохих практик написания кода на Python, с которыми вы, вероятно, столкнетесь.
Использование распаковки для написания компактного кода
Упаковка и распаковка — мощные инструменты Python. Вы можете использовать распаковку для присвоения значений переменным:Вы можете использовать это для написания, пожалуй, самого компактного кода, меняющего значения переменных.>>> a, b = 2, 'my-string' >>> a 2 >>> b 'my-string'
>>> a, b = b, a
>>> a
'my-string'
>>> b
2
Это потрясающе!
Распаковку также можно использовать для присвоения значений нескольким переменным в более сложных случаях.
Например, вы можете написать так: >>> x = (1, 2, 4, 8, 16)
>>> a = x[0]
>>> b = x[1]
>>> c = x[2]
>>> d = x[3]
>>> e = x[4]
>>> a, b, c, d, e
(1, 2, 4, 8, 16)
Но вместо этого вы также можете использовать более краткий и, возможно, более читабельный способ: >>> a, b, c, d, e = x
>>> a, b, c, d, e
(1, 2, 4, 8, 16)
Это круто, правда? Но можно написать ещё круче: >>> a, *y, e = x
>>> a, e, y
(1, 16, [2, 4, 8])
Хитрость в том, что переменная с * собирает значения, которые не присвоены другим переменным.
Использование цепочки для написания компактного кода
Python позволяет объединять операторы сравнения в цепочку.
Таким образом, вам не нужно проверять, верны ли два или более сравнения: >>> x = 4
>>> x >= 2 and x <= 8
True
Вместо этого можно использовать более компактную форму записи: >>> 2 <= x <= 8
True
>>> 2 <= x <= 3
False
Python также поддерживает присвоение переменных по цепочке.
Итак, если вы хотите назначить такой же присваивать значение нескольким переменным одновременно, это можно сделать простым способом: >>> x = 2
>>> y = 2
>>> z = 2
Более компактный способ — использовать распаковку: >>> x, y, z = 2, 2, 2
Однако все выглядит еще круче, если вы используете цепное присвоение: >>> x = y = z = 2
>>> x, y, z
(2, 2, 2)
Будьте осторожны, когда значения разные! Все переменные относятся к одному и тому же значению.
Проверьте отсутствие
None не является уникальным объектом в Python. Имеет аналоги, например, null в C-подобных языках.Вы можете проверить, ссылается ли переменная на None, используя операторы сравнения.
== И != : >>> x, y = 2, None
>>> x == None
False
>>> y == None
True
>>> x != None
True
>>> y != None
False
Однако предпочтительнее использовать является И не является : >>> x is None
False
>>> y is None
True
>>> x is not None
True
>>> y is not None
False
Причем лучше использовать дизайн x не имеет значения «Нет» , а не менее читаемый вариант ( х — нет ).
Перечисление последовательностей и отображений
Вы можете реализовать циклы в Python несколькими способами.Python предлагает несколько встроенных классов, упрощающих их реализацию.
Вы почти всегда можете использовать диапазон для создания цикла, производящего целые числа: >>> x = [1, 2, 4, 8, 16]
>>> for i in range(len(x)):
.
print(x[i]) .
1
2
4
8
16
Однако есть лучший способ сделать это: >>> for item in x:
.
print(item) .
1
2
4
8
16
Но что, если вы хотите запустить цикл в обратном порядке? Конечно, вы можете снова использовать диапазон: >>> for i in range(len(x)-1, -1, -1):
.
print(x[i]) .
16
8
4
2
1
Но «перевернуть» последовательность — более компактный способ: >>> for item in x[::-1]:
.
print(item) .
16
8
4
2
1
Pythonic-способ заключается в использовании обратной последовательности для создания цикла, который будет возвращать элементы последовательности в обратном порядке: >>> for item in reversed(x):
.
print(item) .
16
8
4
2
1
Иногда необходимы как элементы последовательности, так и соответствующие им индексы: >>> for i in range(len(x)):
.
print(i, x[i]) .
0 1
1 2
2 4
3 8
4 16
Лучше использовать перечисление, чтобы получить еще один цикл, возвращающий значения индекса и элемента: >>> for i, item in enumerate(x):
.
print(i, item) .
0 1
1 2
2 4
3 8
4 16
Отлично.
Но что, если вам нужно перебрать две или более последовательностей? Конечно, вы можете снова использовать диапазон: >>> y = 'abcde'
>>> for i in range(len(x)):
.
print(x[i], y[i]) .
1 a
2 b
4 c
8 d
16 e
В этом случае Python также предлагает лучшее решение.
Вы можете подать заявку молния : >>> for item in zip(x, y):
.
print(item) .
(1, 'a')
(2, 'b')
(4, 'c')
(8, 'd')
(16, 'e')
Вы также можете совместить этот метод с распаковкой: >>> for x_item, y_item in zip(x, y):
.
print(x_item, y_item) .
1 a
2 b
4 c
8 d
16 e
Имейте в виду, что диапазон может быть весьма полезным.
Однако бывают случаи (например, описанные выше), когда лучше использовать альтернативы.
Итерация по словарю дает его ключи: >>> z = {'a': 0, 'b': 1}
>>> for k in z:
.
print(k, z[k]) .
a 0
b 1
Однако вы можете использовать метод .
предметы() и получите ключи и соответствующие им значения: >>> for k, v in z.items():
.
print(k, v) .
a 0
b 1
Вы также можете использовать методы .
keys() И .
ценности() для перебора ключей и значений соответственно.
Сравнение с нулем
Когда у вас есть числовые данные и вам нужно проверить, равны ли числа нулю, вы можете (но не всегда нужно) использовать операторы сравнения.
== И != : >>> x = (1, 2, 0, 3, 0, 4)
>>> for item in x:
.
if item != 0: .
print(item) .
1
2
3
4
Способ, которым предлагает Python, — это интерпретировать значение null как ЛОЖЬ , а все остальные числа имеют вид Истинный : >>> bool(0)
False
>>> bool(-1), bool(1), bool(20), bool(28.4)
(True, True, True, True)
Имея это в виду, вы можете использовать если предмет вместо если товар! = 0 : >>> for item in x:
.
if item: .
print(item) .
1
2
3
4
Вы можете следовать той же логике и использовать если не предмет вместо если элемент == 0 .
Как избежать изменяемых необязательных аргументов
Python имеет очень гибкую систему предоставления аргументов функциям и методам.Необязательные аргументы являются частью этого.
Но будьте осторожны: обычно нежелательно использовать изменяемые необязательные аргументы.
Рассмотрим следующий пример: >>> def f(value, seq=[]):
.
seq.append(value) .
return seq
На первый взгляд это выглядит так, если вы не укажете последовательность , е() добавляет ценить в пустой список и возвращает что-то вроде [значение]: >>> f(value=2)
[2]
Выглядит великолепно, не так ли? Нет! Рассмотрим следующие примеры: >>> f(value=4)
[2, 4]
>>> f(value=8)
[2, 4, 8]
>>> f(value=16)
[2, 4, 8, 16]
Удивлен? Если да, то вы не одиноки.
Кажется, что каждый раз, когда вызывается функция, предоставляется один и тот же экземпляр необязательного аргумента (в данном случае списка).
Возможно, иногда это будет то, что вам нужно.
Однако гораздо более вероятно, что вам придется этого избегать.
Один из способов заключается в следующем: >>> def f(value, seq=None):
.
if seq is None: .
seq = [] .
seq.append(value) .
return seq
Меньшая версия: >>> def f(value, seq=None):
.
if not seq: .
seq = [] .
seq.append(value) .
return seq
Теперь мы получаем другой результат: >>> f(value=2)
[2]
>>> f(value=4)
[4]
>>> f(value=8)
[8]
>>> f(value=16)
[16]
В большинстве случаев это то, что вам нужно.
Избегание классических методов получения и установки
Python позволяет определять методы получения и установки точно так же, как C++ и Java: >>> class C:
.
def get_x(self):
.
return self.__x
.
def set_x(self, value):
.
self.__x = value
Вот как вы можете их использовать:
>>> c = C()
>>> c.set_x(2)
>>> c.get_x()
2
В некоторых случаях это лучший способ.
Однако зачастую лучше использовать свойства, особенно в простых случаях: >>> class C:
.
@property .
def x(self): .
return self.__x .
@x.setter .
def x(self, value): .
self.__x = value
Свойства считаются более Pythonic, чем классические геттеры и сеттеры.
Их можно использовать так же, как в C#, то есть как обычные атрибуты данных: >>> c = C()
>>> c.x = 2
>>> c.x
2
Итак, в общем, лучше использовать свойства, когда это возможно.
Избегание доступа к защищенным членам класса
В Python нет частных членов класса как таковых.Однако если вы напишете (_) в начале имени элемента, то доступ к его изменению вне класса будет запрещен.
Например, рассмотрим код: >>> class C:
.
def __init__(self, *args): .
self.x, self._y, self.__z = args .
>>> c = C(1, 2, 4)
Экземпляры класса C имеют три элемента данных: .
x, .
y и .
_Cz. Если имя участника начинается с двойного подчеркивания (дандер), оно становится измененным.
Вот почему вместо .
_z используется элемент .
_Cz. Теперь вы можете получить доступ к .
x или изменить его напрямую: >>> c.x # OK
1
Вы также можете получить доступ к .
_y или изменить его вне его класса, но это считается дурным тоном: >>> c._y # Possible, but a bad practice!
2
Вы не можете получить доступ к .
z, поскольку переменная изменена, но вы можете получить доступ или изменить .
_Cz: >>> c.__z # Error!
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'C' object has no attribute '__z'
>>> c._C__z # Possible, but even worse!
4
>>>
Вам следует избегать этого.
Автор класса, вероятно, начинает имена с подчеркивания, чтобы подчеркнуть, что лучше не использовать элемент вне его класса.
Использование менеджеров контекста для освобождения ресурсов
Иногда вам нужно написать код для правильного управления ресурсами.Это часто происходит при работе с файлами, подключениями к базе данных или другими объектами с неуправляемыми ресурсами.
Например, вы можете открыть файл и обработать его: >>> my_file = open('filename.csv', 'w')
>>> # do something with `my_file`
Чтобы правильно распоряжаться памятью, после окончания работы необходимо закрыть этот файл: >>> my_file = open('filename.csv', 'w')
>>> # do something with `my_file and`
>>> my_file.close()
Делать это таким образом лучше, чем не делать этого вообще.
Но что, если при обработке файла возникнет исключение? Тогда my_file.close() никогда не выполняется.
Вы можете справиться с этим, используя обработку исключений или используя менеджеры контекста.
Второй способ означает, что вы помещаете свой код в блок.
с : >>> with open('filename.csv', 'w') as my_file:
.
# do something with `my_file`
Использование блока with означает, что специальные методы .
входить() И .
Выход() вызываются даже в исключительных случаях.
Эти методы должны заботиться о ресурсах.
Вы можете добиться особенно надежного проектирования, объединив менеджеры контекста и обработку исключений.
Стилистические советы
Код Python должен быть элегантным, кратким и читаемым.
Основным ресурсом о том, как писать красивый код Python, является Руководство по стилю для кода Python, или PEP 8. Вам следует прочитать его, если вы хотите писать код Python.
выводы
В этой статье даются несколько советов о том, как писать более компактный и читаемый код. Короче говоря, он показывает, как сделать ваш код более Pythonic. Кроме того, PEP 8 содержит Руководство по стилю кода Python, а PEP 20 знакомит с принципами языка Python. Наслаждайтесь написанием полезного и красивого кода! Спасибо за чтение.Теги: #python #программирование #перевод #phyton #краткость
-
Программирование Под Дулом Пистолета
19 Oct, 24 -
Podthings, Выпуск 17
19 Oct, 24