Несколько вещей, которые я узнал, работая с Python
Нужно различать внутренние и внешние переменные класса
В Python для объявления переменных класса обычно используется объект self, но это, строго говоря, способ объявления внутренних переменных экземпляра. Для доступа к переменной класса таким способом требуется создание экземпляра. Если нужно гарантировать одинаковое значение для всех объектов или добиться эффекта, похожего на ключевое слово static в C# или Java, переменную следует объявлять вне __init__().
class Person:
''' Можно объявить следующим образом.
'''
type = "person"
def __init__(self):
self.name = name
self.age = age
# ...
Эта переменная будет доступна всем экземплярам с одним и тем же значением. При этом следует помнить, что доступ к ней, даже внутри самого объекта, осуществляется как Имя_класса.Имя_переменной. Например, если внутри класса People нужно изменить значение переменной type на another_people_type, можно обратиться к ней как People.type = another_people_type.
В Python тоже можно использовать геттеры и сеттеры
Хотя они не называются getter и setter, как в C# или Java, концепция соединения внутренней переменной класса и публичного свойства та же. Это полезно не только для сокрытия внутренних переменных, но и, что более удобно, для привязки логики к изменению значения переменной.
class Example:
def __init__(self):
self._variable = None
@property
def variable(self):
return self._variable
@variable.setter(self, value):
self._variable = value
Как и в других языках, если объявить только @property без сеттера, попытка изменить значение через это свойство вызовет ошибку, так что нужно быть внимательным.
В имени модуля можно отражать количество классов
По умолчанию функции — это единица классификации кода, классы — единица классификации функций и переменных, модули — единица классификации классов. Один из способов лучше реализовать эту концепцию — если в одном модуле несколько классов, просто указывать имя модуля во множественном числе.
myproject/
│
├── app/
│ ├── users/
│ │ ├── models.py
│ │ ├── views.py
│ │ └── controllers.py
│ ├── products/
│ └── orders/
│
└── main.py
В этом случае в models.py можно использовать имена формата «имя + тип», например UserModel() или ProductModel (хотя это не конкретный пример из реального проекта). Такая структура даёт более чёткую классификацию классов по сравнению со случаем, когда в одном модуле только один класс, и позволяет использовать естественные конструкции при импорте: from models import UserModel as UM.
Интуитивно понятные имена лучше метафор
Интуитивность метафор в большинстве случаев половинчатая. Первая половина делает код лаконичным и более интересным для чтения при первом знакомстве, но вторая половина делает намерение, стоящее за кодом, размытым. Поэтому, на мой взгляд, по возможности лучше их избегать.
def main():
''' Пример с темой ювелира
'''
self.mining()
self.cutting()
self.crafting()
self.selling()
def main()
''' Пример с темой шеф-повара высокой кухни
'''
self.washing()
self.cutting()
self.cooking()
self.plating()
Я пробовал структурировать код с помощью различных метафор, например, как показано выше — сравнивая общий процесс с продажей драгоценностей (добыча-огранка-обработка-продажа) или имитируя процесс приготовления блюда шеф-поваром (мойка-нарезка-приготовление-сервировка). Но проблема была в том, что имена функций, построенные на метафорах, нечётко отражали реальную роль кода.
Из-за этого добавлялся дополнительный шаг в процессе понимания смысла, что создавало излишние трудности для других людей (или для меня самого в будущем) при чтении кода. Иногда даже происходила путаница, и писатель начинал больше думать о соблюдении темы класса или функции, чем о сути.
Вместо этого, пусть и менее занимательно, оказалось чище описывать роль класса стандартным образом.
def main():
''' Просто обычный случай
'''
download_data()
basic_process()
save_results()
Возможно, метафоры уместны, если вспомогательный образ, используемый для сравнения (например, цитаты из исторических событий или известные истории), обладает подавляющей интуитивностью. Но в большинстве остальных случаев более практичным оказалось просто и лаконично описывать то, что делает код.