olamundo
olamundo

Reputation: 24981

Do python packages (multi-file modules) behave exactly as one big module?

I've just read an article that supposedly introduced me to a new concept: Up to now I was sure that python packages (i.e directories with an __init__.py file) behave exactly the same as java packages, that is - little namespaces to help arrange the code (minus java's "package" scoping). But, according to this link: A Short Digression Into Multi-File Modules, if I put all my files in the same "package":

the entire collection of files is presented to other Python code as a single module — as if all the functions and classes were in a single .py

So now I thought that my whole understanding of the python "package" thing was wrong. Moreover - it's entirely not a package, rather a "multifile module" as the author refers to it.

So, from what I understood, no matter to how many files I divide my funcs and classes inside a package, from the outside that package should appear as though I took all the code from all the files inside the package and put it in one big file with the same name as the package instead, i.e as one module.

e.g, if I have the following file structure:

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

and in dog.py:

def bark():
    print "woof"

it should be exactly the same as having:

/base
    /animals.py

and in animals.py:

def bark():
    print 'woof'

thus, this next piece of code should run fine on both cases:

from base import animals
animals.bark()

This of course yields in the first case:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'module' object has no attribute 'bark'

What am I missing here? I see by the exception that "animals" is indeed treated as a module, but it appears i still have to explicitly state animals.dog.bark, i.e the internal file structure of the package isn't abstracted from the outside.

Am I missing the author's point, or just not implementing it correctly?

=== EDIT ===

Just to make sure no one misses this line in the quote:

as if all the functions and classes were in a single .py

regardless of how to actually access this funcs and classes, the above quote explicitly states that if you have a func1 in file a and func2 in file b, regardless of which path will they be accessible from, if we denote this path as X then, according to the aforementioned quote, both X.func1 and X.func2 should work.

Upvotes: 10

Views: 1715

Answers (4)

Elmar Zander
Elmar Zander

Reputation: 1516

Not a real answer, but as I'm not yet allowed to comment (sigh!):

Since diveintopython is much used/cited/referenced resource for Python programmers (at least when they begin with), you should really contact the author about this flaw as it will be misleading also to others. There is some contact information on the home page of diveintopython3 and you can also file it as an issue on github.

Upvotes: 1

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798606

The author has oversimplified things. He's saying that everything under animal can be seen as being in the same module, although the fact is that names in animal.dog will be in their own namespace.

Upvotes: 4

Nikwin
Nikwin

Reputation: 6756

I can't really explain it well, but maybe the following code will help. If I leave your first file structure as it is, and instead modify the second to have the following in the animals.py file:

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

Then in both cases,

from base import animals
animals.dog.bark()

will work.

Upvotes: 0

u0b34a0f6ae
u0b34a0f6ae

Reputation: 49793

Maybe the point is simply that a package is just a specific type of module.

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

It just means that anything that you define in or import into __init__.py will be visible inside the animals module.

So animals is a module (that is a package) and animals.dog is a module that is a submodule of animals, but not a package.

It also means that if you have a simple module animals you can supercede it by a package by the same name in the next version, and arrange so that your users won't notice the difference.

If you want that all classes from the package's submodules make up one single user-visible module (namespace), you have to define a line like this for each submodule, in __init__.py:

from animals.dog import *

Upvotes: 4

Related Questions