> The book "Code Complete" recommends that you put only one class in a > source file, which seems a bit extreme for me. It seems that many > classes are small, so that putting several of them in a file seems > reasonable. I noticed that the decimal.py module in the standard > library has several classes, all of which of course revolve around the > "decimal" topic. Perhaps a better rule of thumb is "one idea per > file." I checked the Python style guide and there seems to be no > mention of this topic. I know this is an elementary question, but what > is the Python way of doing this?
I'm in a similar situation. I've been reading Robert C. Martins book "Agile Software Development" and he suggests something similar. I would highly recommend that book by the way. He also has a couple of chapters on packaging where he makes some very good points about the reasoning behind it. Basically that you want to organize your code in such a way that package dependencies move in the direction of increasing stability. In this case stability is a metric which is defined as how likely the code is going to change in the future as determined by how many packages depend on it as opposed to how many packages it depends on. He paints a couple of scenarios in which he groups packages together that _seem_ to be related, only to see that it results in all of his packages needing to be re-built every time a change is required. Obviously we don't have to re-build python code, but it is still useful to organize your code in such a way that you don't have to constantly re-visit collections of code. I have actually started using his suggestion and have been putting one class per file. When one class depends on another I include it with a "from x import X". This makes it very easy to determine the dependencies (well, the non-abstract dependencies anyway, interfaces are a different story*). Then I put all of my classes together in a package, and make the "public" classes visible on a package level by importing them into the package __init__ module. With that being said, If I made a class that was _only_ used by one other single class, and it was clear that it would never be made visible outside of that file, I would certainly put it in the same file as that class. Heck, you might even refactor your code and determine at that time that some piece of code is only used by one other piece. It is much easier to put code together after the fact than it is to separate it, especially later in the game. My advice: don't knock it until you try it. I think my code has improved quite a bit since taking this advice. It can be much more difficult to determine which classes to package together until much later in the development cycle. One thing that can help is to find an IDE that helps you to easily switch between files. I use WingIDE, but I have even used vim with a tags file and it wasn't terrible. I wouldn't call it a hard rule, but at the same time I wouldn't just ignore it. Give it a shot and adapt your development technique to see what works best for you. Example: [mypackage/__init__.py] __all__ = ["X"] from .x import X [end mypackage/__init__.py] [mypackage/x.py] from .y import Y __all__ = ["X"] class X(object): # code - using Y hopefully [end mypackage/x.py] [mypackage/y.py] __all__ = ["Y"] class Y(object): # code [end mypackage/y.py] Matt * Interfaces in python represent an implicit dependency. The Zen of Python states: "Explicit is better than implicit". I plan to experiment with the ABC module in python 2.6/3.0. I want to make my interfaces explicitly defined, but on the other hand I still want it to be easy for people who use my code to duck-type. This _seems_ to be possible since you can .register a class with an interface after it has been created, but I'm not sure that it is very pythonic to explicitly check for an interface every time it is used. It would seem silly however to import an interface into a file where it isn't explicitly used just to document the dependency. If anybody has pointers let me know. -- http://mail.python.org/mailman/listinfo/python-list