views:

187

answers:

3

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: http://diveintopython3.org/case-study-porting-chardet-to-python-3.html#multifile-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.

+2  A: 

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 *
kaizer.se
please see the edit I added to my question - I think it clearly shows this answer misses the author's point (unless I am also missing something in your answer :))
noam
the text you link to is certainly wrong and easy to misunderstand. but my answer is simply what I think is a sensible answer to a closely related question, and it also shows how you can make it true -- how you can make it look like all the functions and classes are defined in the same .py file. The linked text implies this is automatic, but it is not, it is a mere possibility.
kaizer.se
However on a higher level, what is written *is* true, since a package gathers the content of as many .py files as you want behind a single top-level modulename. However, it doesn't gather all attributes immediately in the module namespace.
kaizer.se
A: 

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.

Nikwin
well, yeah, in that specific case both will work. But the author's claim is much more stronger than that - modules behave as one big module.What you've proved is that modules in a package behave kinda like as one big module with properties, something which I believe most people do know :)Quote form the author: "as if all the *functions* and *classes* were in a single .py" - this explicitly means that animals.bark should suffice.
noam
+4  A: 

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.

Ignacio Vazquez-Abrams
OK, good. I thought I was missing something :)
noam