views:

77

answers:

3

I asked a similar question yesterday, but have acquired a really odd problem since then. With this directory structure:

app/
    models/
        __init__.py
        user.py
        other.py
    pages/
        __init__.py
        pages.py

The models/__init__.py file has this line:

__all__ = ['user', 'other']

and the pages/__init__.py has

__all__ = ['pages']

In pages.py, in order to use any of the classes in user.py or other.py, I have to have

from models import *
import models

at the top, and then I can declare a User class like this:

my_user = models.user.User()

If I exclude either of the import-ing statements at the top, I get errors like

"Class user has no attribute User"

Any help would be appreciated. I love Python, but I wish it's import functionality worked more like PHP's.

A: 
import models.user
Ignacio Vazquez-Abrams
+2  A: 

There are two options, depending on where you want to be explicit and how much you want available "by default" (which also means forced).

In those __init__ files you could use:

# models/__init__.py shown:
import user, other                 # ambiguous relative import
from . import user, other          # relative import
from app.models import user, other # absolute import

Or, where you would otherwise just have import models, use:

from models import user, other
# or:
import models.user, models.other

The latter form is more widely preferred.

Roger Pate
i put `from app.models import user, other` and it works great, thanks
W_P
+1  A: 

One thing that can be real helpful when you're learning python (or debugging), is to run interactively and use the dir() function to see what lives where:

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']
>>> import models
>>> dir(models)
['__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
>>> models.user
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'user'
>>> from models import *
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'models', 'other', 'user']
>>> dir(models)
['__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__','__path__', 'other', 'user']
>>> user
<module 'models.user' from 'C:\test\models\user.py'>
>>> models.user
<module 'models.user' from 'C:\test\models\user.py'>
>>> user.User
<class 'models.user.User'>

Update: fixed output.

Seth
What is the content of your models/\_\_init\_\_.py? As the question is stated, `import models; models.user` will give an AttributeError. (Does your sample have `import user` in models/\_\_init\_\_.py? That would explain your different results.)
Roger Pate
@Roger - my models/__init__.py is just `__all__ = ['user', 'other']`.
Seth
@Seth: Then I'd expect you to get what I get: http://codepad.org/yWnKyVAW. Did you have an earlier `import models.user` or similar? (That import will modify the models module object.)
Roger Pate
when i just use import models _or_ from models import * and run dir(models) i get "['__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']". I have to have both of those statements in order for users and other to be included.
W_P
@Roger I see what the problem is now. I had leftovers in the local scope from doing a `from models import *`. Fixed it up.
Seth