Ответ 1
Автор имеет упрощенные вещи. Он говорит, что все под animal
можно рассматривать как находящиеся в одном модуле, хотя факт состоит в том, что имена в animal.dog
будут находиться в собственном пространстве имен.
Я только что прочитал статью, которая предположительно представила мне новую концепцию: до сих пор я был уверен, что пакеты python (то есть каталоги с файлом __init__.py
) ведут себя точно так же, как java-пакеты, то есть - мало пространства имен, которые помогут упорядочить код (минус java "пакет" ).
Но, согласно этой ссылке:
Короткое отступление в многофайловых модулях, если я поместил все мои файлы в один и тот же "пакет":
вся коллекция файлов представлена в другом коде Python как один модуль - как если бы все функции и классы были в одном .py
Итак, теперь я подумал, что все мое понимание "пакета" python было неправильным. Более того - это полностью не пакет, а скорее "мультифильный модуль", как автор ссылается на него.
Итак, из того, что я понял, независимо от того, сколько файлов я делю мои funcs и классы внутри пакета, снаружи этот пакет должен выглядеть так, как если бы я взял весь код из всех файлов внутри пакета и поместил его в одном большом файле с тем же именем, что и пакет, т.е. как один модуль.
например, если у меня есть следующая файловая структура:
/base
/animals
/__init__.py
/dog.py
и в dog.py:
def bark():
print "woof"
он должен быть точно таким же, как:
/base
/animals.py
и в animal.py:
def bark():
print 'woof'
таким образом, этот следующий фрагмент кода должен работать нормально в обоих случаях:
from base import animals
animals.bark()
Это, конечно, дает в первом случае:
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'module' object has no attribute 'bark'
Что мне здесь не хватает? Я вижу, за исключением того, что "животные" действительно рассматриваются как модуль, но, похоже, я все же должен явно указывать animals.dog.bark
, то есть внутренняя файловая структура пакета не абстрагируется снаружи.
Я пропущу точку автора или просто не выполнил ее правильно?
=== EDIT ===
Просто чтобы убедиться, что никто не пропустил эту строку в цитате:
как если бы все функции и классы находились в одном .py
независимо от того, как реально получить доступ к этим функциям и классам, приведенная выше цитата явно заявляет, что если у вас есть func1 в файле a и func2 в файле b, независимо от того, с каким путем они будут доступны, если мы обозначим этот путь как X, то, согласно вышеупомянутой цитате, должны работать как X.func1
, так и X.func2
.
Автор имеет упрощенные вещи. Он говорит, что все под animal
можно рассматривать как находящиеся в одном модуле, хотя факт состоит в том, что имена в animal.dog
будут находиться в собственном пространстве имен.
Возможно, дело просто в том, что пакет - это всего лишь определенный тип модуля.
/base
/animals
/__init__.py
/dog.py
Это означает, что все, что вы определяете или импортируете в __init__.py
, будет видно внутри модуля animals
.
So animals
- это модуль (это пакет), а animals.dog
- это модуль, который является подмодулем animals
, но не пакетом.
Это также означает, что если у вас есть простой модуль animals
, вы можете переустановить его пакетом с тем же именем в следующей версии и организовать так, чтобы ваши пользователи не заметили разницы.
Если вы хотите, чтобы все классы из подмодулей пакета составляли один единственный видимый для пользователя модуль (пространство имен), вы должны определить такую строку для каждого подмодуля в __init__.py
:
from animals.dog import *
Не настоящий ответ, но поскольку мне еще не разрешено прокомментировать (вздох!):
Так как diveintopython много используется/цитируется/ссылается ресурс для программистов Python (по крайней мере, когда они начинаются), вы должны действительно связаться с автором об этом недостатке, поскольку он будет вводить в заблуждение и другим. На домашней странице diveintopython3 есть какая-то контактная информация, и вы также можете указать ее как проблему в github.
Я не могу объяснить это хорошо, но, возможно, следующий код поможет. Если я оставлю свою первую файловую структуру так, как она есть, и вместо этого изменим вторую, чтобы иметь следующий файл animal.py:
class Dog:
def bark(self): pass
dog=Dog()
Тогда в обоих случаях
from base import animals
animals.dog.bark()
будет работать.