воскресенье, 1 ноября 2020 г.

ЛМНты Python, 86 - 90

>>> Стиль имеет значение

PEP8 – это руководство по стилю кодирования на Python. PEP8 рекомендует, чтобы имена функций и переменных использовали буквы только в нижнем регистре и _ (подчеркивание) в качестве разделителя слов:

i
name
full_name

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

Согласно PEP8, идентификаторы в стандартной библиотеке Python могут использовать только символы ASCII. Разумно распространить это соглашение на свой код, хотя технически такого ограничения в Python 3 нет:

>>> # не нужно так делать
>>> привет = 'Hello'
>>> привет
'Hello'
>>>

>>> Статический метод

Статический метод в классе определяется с помощью декоратора staticmethod. Это обычный метод в пространстве имен класса, при его вызове неявные аргументы не передаются.

>>> class C:
...     @staticmethod
...     def answer():
...         return 42
...
>>> C.answer()
42
>>> C().answer()
42

Таким образом, статический метод не имеет доступа к классу (через cls, как класс-метод) или экземпляру класса (через self, как инстанс-метод).

>>> Стиль влияет

Согласно PEP8, имена, начинающиеся с _ (подчеркивание), предназначены для использования только внутри модуля, в котором они определены. Поэтому предложение

from module import *

такие имена не импортирует, если только они явно не включены в список импорта __all__ в модуле.

Отсюда, чтобы предотвратить импорт глобальных переменных из вашего модуля предложением from module import *, начинайте их имена с _ или используйте __all__ для ограничения "экспортируемых" модулем имен.

>>> Соглашение, а не запрет

Пусть будет модуль:

# my.py
__all__ = ["salut"]

hello = 'Hello!'
salut = 'Salut !'
_memo = 'Use it or lose it'

Импортировав имена из модуля с помощью *, проверим их доступность:

>>> from my import *
>>> salut
'Salut !'
>>> hello
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'hello' is not defined
>>> _memo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name '_memo' is not defined

Итак, разработчик модуля явно объявил "экспортируемые" им имена в списке __all__. Explicit is better than implicit, как учит Python Zen. Следуя этой же добродетели, импортировать имена из модуля нужно явно (а не злоупотреблять звездочкой):

>>> from my import _memo
>>> _memo
'Use it or lose it'

"Приватность" переменной _memo и ее отсутствие в списке __all__ не мешают импортировать ее явно. Таким образом, и приватность переменных и спецификация публичных имен – в Python только удобные соглашения, позволяющие разработчику заявить о намерениях.

>>> Родитель один, родитель два, ...

Объектная модель Python поддерживает множественное наследование классов. В результате,

  1. дерево наследования превращается в граф с циклами и
  2. возникает возможность конфликта имен из родительских классов.
Например:
>>> class A:
...     def whoami(self):
...         print('A')
...
>>> class B:
...     def whoami(self):
...         print('B')
...
>>> class AB(A, B):
...     pass
...

Вызов AB().whoami() выведет на экран A или B или сломается?

>>> AB().whoami()
A

Такое поведение определяется порядком разрешения имен методов (MRO, method resolution order), принятым в Python: слева направо снизу вверх (сначала родители, потом деды, и так далее...)

>>> class BA(B, A):
...     pass
...
>>> BA().whoami()
B

Список предков класса, отсортированный в порядке "удаленности", называют линеаризацией. Для класса AB линеаризация будет [A, B, object]. Видите цикл в графе наследования класса AB?

Комментариев нет:

Отправить комментарий