views:

372

answers:

3

I am developing a Python App Engine app, where I want to split the content of a source code file Models.py into separate files for each model, but I want to put it all in a folder called Models. The problem is that when I do that, my app can't find the classes anymore. What should I do?

This question is not about MVC but another question with the same title is.

+9  A: 

Put an empty __init__.py file in the Models directory.

Then, in your app; presumably one level up, you reference modules in the Models directory like this:

import Models

and do something with it like this:

Models.my_model.MyClassName

You can also use the from keyword like this:

from Models import my_model

and reference like this:

my_model.MyClassName

If you only need one method from a module, you could also do this:

from Models.my_model import my_method_name
my_method_name()

Obligatory link to the documentation.

Adam Bernier
I voted this up, with the cavet that module and package names should be lowercase. and that directories with ____init____.py files are packages not modules.
fuzzy lollipop
@fuzzy: thanks for adding that.
Adam Bernier
@fuzzy: I don't think I claimed that a package is a module.
Adam Bernier
the problem with splitting classes into different files in Python is that I have to add the module prefix wherever I use it. This is cumbersome and it doesn't happen in C#
Jader Dias
@Jader: You can avoid having to do this by importing the specific classes you need explicitly with `from module import ClassName`.
Adam Bernier
@Adam I got that, the problem is that if I use 10 classes in 10 different modules I will have to write 10 imports
Jader Dias
@Jader Dias, Python modules may contain 0, 1, multiple classes. Modules help to organize them for use and thought, and a given module should have as many classes as make sense. Avoiding import lines is a minor concern. Multiple classes in one module makes sense if and because they are closely-related.
Mike Graham
@Jader: and your point is ... what? You prefer to have automagical pollution of your namespace? If you need do this once in one file it will take you less time to *do it* than to make a comment here. If you find yourself doing this in many places then it's time to understand Python's package mechanism, the use of the __init__.py file (hint: it's not just to be an empty file), and other ways of bringing multiple, disparate functions into scope. See http://docs.python.org/tutorial/modules.html#packages for all of the exciting details.
Peter Rowell
If you don't want Models to be a package, skip the __init__.py and add the Models directory to sys.path; you should then be able to import the files contained there directly. Or don't put them all in a subdirectory in the first place; do you really have so many project files that this is necessary?
Wooble
@Mike @Peter @Wooble Please keep in mind that I am used to other languages where each file content usually fit one screen and more than one class per file is a major sin
Jader Dias
@Wooble, modifying `sys.path` isn't something you can do in a real program. It makes programs fragile and unportable.
Mike Graham
@Mike Graham: App Engine is a controlled environment. You don't have to worry much about portability; since the entire set of APIs you'll be using will make it unportable in the first place.
Wooble
+1  A: 

Adam Bernier provides a good technical description of how packages work. A great description of how to arrange and ship a project is described in http://jcalderone.livejournal.com/39794.html

Mike Graham
+1 for the informative link
Adam Bernier
+3  A: 

In response to your comment to Adam's answer, regarding having 10 imports for 10 classes, firstly don't forget that there's no need to have one class per module in Python. Modules should be organised by functionality, so you can group related classes in a single file if that makes sense.

If you still wanted to make all the classes importable in one go, you could import them all in the __init__.py file itself using the from submodule import Class syntax, then just import the containing module - import mainmodule and refer to mainmodule.Class1 etc, or even use from mainmodule import Class1, Class2, Class3 to import the classes directly into your namespace and refer to them directly.

Daniel Roseman