Пакеты python (многофайловые модули) ведут себя точно так же, как один большой модуль?

Я только что прочитал статью, которая предположительно познакомила меня с новой концепцией: до сих пор я был уверен, что пакеты python (то есть каталоги с файлом __init__.py) ведут себя точно так же, как пакеты java, то есть - небольшие пространства имен, помогающие упорядочить код (минус область видимости "пакета" java). Но, согласно этой ссылке: A Краткий экскурс в многофайловые модули, если я помещу все свои файлы в один «пакет»:

вся коллекция файлов представлена ​​другому коду Python как единый модуль - как если бы все функции и классы находились в одном .py

Итак, теперь я подумал, что все мое понимание «пакета» Python было неправильным. Более того - это совсем не пакет, а «многофайловый модуль», как его называет автор.

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

например, если у меня следующая файловая структура:

/base
    /animals
        /__init__.py
        /dog.py

и в dog.py:

def bark():
    print "woof"

он должен быть таким же, как и наличие:

/base
    /animals.py

и в animals.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, т.е. внутренняя файловая структура пакета не абстрагируется извне.

Я упускаю точку зрения автора или просто неправильно ее реализую?

=== РЕДАКТИРОВАТЬ ===

Просто чтобы убедиться, что никто не пропустил эту строчку в цитате:

как если бы все функции и классы находились в одном .py

независимо от того, как на самом деле получить доступ к этим функциям и классам, в приведенной выше цитате явно указано, что если у вас есть func1 в файле a и func2 в файле b, независимо от того, по какому пути они будут доступны, если мы обозначим этот путь как X, тогда, согласно вышеупомянутой цитате должны работать и X.func1, и X.func2.


person olamundo    schedule 06.03.2010    source источник
comment
Я не смог найти эту цитату на связанной странице. Хотите попробовать еще раз?   -  person Ignacio Vazquez-Abrams    schedule 06.03.2010
comment
@Ignacio: diveintopython3.org/   -  person unutbu    schedule 06.03.2010
comment
@ignacio - извините, поправил ссылку   -  person olamundo    schedule 06.03.2010


Ответы (4)


Автор все сильно упростил. Он говорит, что все в animal можно рассматривать как находящееся в одном модуле, хотя на самом деле имена в animal.dog будут находиться в своем собственном пространстве имен.

person Ignacio Vazquez-Abrams    schedule 06.03.2010

Может быть, дело просто в том, что пакет - это просто модуль определенного типа.

/base
    /animals
        /__init__.py
        /dog.py

Это просто означает, что все, что вы определяете или импортируете в __init__.py, будет видно внутри модуля animals.

Итак, animals - это модуль (то есть пакет), а animals.dog - это модуль, который является подмодулем animals, но не пакетом.

Это также означает, что если у вас есть простой модуль animals, вы можете заменить его пакетом с тем же именем в следующей версии и расположить так, чтобы ваши пользователи не заметили разницы.

Если вы хотите, чтобы все классы из подмодулей пакета составляли один видимый для пользователя модуль (пространство имен), вы должны определить такую ​​строку для каждого подмодуля в __init__.py:

from animals.dog import *
person u0b34a0f6ae    schedule 06.03.2010
comment
пожалуйста, посмотрите правку, которую я добавил к своему вопросу - я думаю, это ясно показывает, что этот ответ не соответствует точке зрения автора (если я также что-то не упустил в вашем ответе :)) - person olamundo; 06.03.2010
comment
текст, на который вы ссылаетесь, определенно неверен, и его легко понять. но мой ответ - это то, что я считаю разумным ответом на тесно связанный вопрос, и он также показывает, как вы можете сделать это правдой - как вы можете сделать так, чтобы все функции и классы были определены в одном и том же файле .py . Связанный текст подразумевает, что это происходит автоматически, но это не так, это всего лишь возможность. - person u0b34a0f6ae; 06.03.2010
comment
Однако на более высоком уровне то, что написано является истинным, поскольку пакет собирает содержимое столько файлов .py, сколько вы хотите, за одним именем модуля верхнего уровня. Однако он не собирает сразу все атрибуты в пространстве имен модуля. - person u0b34a0f6ae; 06.03.2010

Не настоящий ответ, но поскольку мне еще не разрешено комментировать (вздох!):

Поскольку diveintopython является часто используемым / цитируемым / упоминаемым ресурсом для программистов Python (по крайней мере, когда они начинают с), вам действительно следует связаться с автором по поводу этого недостатка, поскольку он также может ввести в заблуждение других. На домашней странице diveintopython3 есть некоторая контактная информация, и вы также можете указать ее как проблему на github.

person Elmar Zander    schedule 01.11.2011

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

class Dog:
    def bark(self): pass
dog=Dog()

Тогда в обоих случаях

from base import animals
animals.dog.bark()

буду работать.

person Nikwin    schedule 06.03.2010
comment
ну да, в этом конкретном случае оба будут работать. Но утверждение автора намного сильнее этого - модули ведут себя как один большой модуль. Вы доказали, что модули в пакете ведут себя как один большой модуль со свойствами, что, как я полагаю, знает большинство людей :) Цитата от автора: как будто все функции и < i> классы находились в одном .py - это явно означает, что для работы с файлом animals.bark должно быть достаточно. - person olamundo; 06.03.2010