Питонический способ организации модулей и пакетов

Я родом из фона, где обычно создаю один файл для каждого класса. Я также организую общие классы по каталогам. Эта практика интуитивна для меня, и она доказала свою эффективность в С++, PHP, JavaSript и т.д.

У меня возникли проблемы с переносом этой метафоры на Python: файлы больше не просто файлы, а формальные модули. Не похоже, чтобы иметь только один класс в модуле - большинство классов бесполезны сами по себе. Если у меня есть класс automobile.py и Automobile, кажется глупым всегда ссылаться на него как automobile.Automobile.

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

Каков правильный --- или питонический путь? (Или, если нет правильного пути, каков ваш предпочтительный способ и почему?) Сколько кода я должен бросать в модуль Python?

Ответ 1

Подумайте о терминах "логической единицы упаковки", которая может быть одним классом, но чаще будет набор классов, которые тесно сотрудничают. Классы (или функции уровня модуля - не "делают Java в Python", всегда используя статические методы, когда функции уровня модуля также доступны в качестве выбора!) Могут быть сгруппированы на основе этого критерия. В принципе, если большинство пользователей A также нуждаются в B и наоборот, A и B должны, вероятно, находиться в одном модуле; но если многим пользователям нужен только один из них, а не другой, то они, вероятно, должны быть в разных модулях (возможно, в том же пакете, то есть в каталоге с файлом __init__.py).

Стандартная библиотека Python, хотя и далеко не идеальная, имеет тенденцию отражать (в основном) разумно хорошие практики - поэтому вы можете в основном учиться на этом примере. Например, модуль threading, конечно, определяет класс Thread... но он также содержит классы-примитивы синхронизации, такие как блокировки, события, условия и семафоры, а также класс исключений, который может быть поднят потоковыми операциями (и еще несколько вещей). Он находится на верхней границе разумного размера (800 строк, включая пробелы и докстры), а некоторые важные связанные с потоком функции, такие как Queue, были помещены в отдельный модуль, тем не менее это хороший пример того, какой максимальный объем функциональности он имеет смысл для упаковки в один модуль.

Ответ 2

Если вы исходите из точки зрения С++, вы можете просматривать модули python, похожие на .so или .dll. Да, они выглядят как исходные файлы, потому что питон написан по сценарию, но они фактически являются загружаемыми библиотеками определенной функциональности.

Другая метафора, которая может помочь, - это, возможно, посмотреть на модули python как пространства имен.

Ответ 3

Если вы хотите придерживаться вашей системы one-class-per-file (что логично, не поймите меня неправильно), вы можете сделать что-то вроде этого, чтобы не ссылаться на automobile.Automobile:

from automobile import Automobile
car = Automobile()

Однако, как упоминалось cobbal, более чем один класс для файла довольно распространен в Python. В любом случае, пока вы выбираете разумную систему и используете ее последовательно, я не думаю, что пользователи Python будут злиться на вас:).

Ответ 4

В проекте среднего размера я нашел несколько наборов близко родственных классов. Некоторые из этих наборов теперь сгруппированы в файлы; например, низкоуровневые сетевые классы находятся в одном модуле network. Тем не менее, некоторые из самых больших классов были разделены на их собственный файл.

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