Today's post should be pretty light, since all I'm going to cover are the template-files I use as starting-points for modules and packages.
My Module Template
As mentioned (I think) in a previous post, the main reason I use a template
file is so that I don't have to waste a lot of time figuring out how to keep
things organized every time I start a new module or package. An added benefit,
potentially at least, is that all of my module- and package-files
should be consistent enough that someone who's never seen my code can likely
figure out where things are in any of my code after seeing a few smaller chunks of
it elsewhere. I also find that it makes things easier for me to locate
something (where is that abstract class?
) if I've been away from it for any
length of time.
Granted, a good editor/IDE will probably have ways to navigate to something in the current project-structure (Geany and Eclipse both seem to allow ctrl-clicking as a means of jumping to class or variable definitions). When that fails, or is too clunky for some reason (like if there are multiple classes with the same name across several files), I can usually pick out which file I want to look in, and navigate to one of the comment-headers very quickly.
Your mileage may vary...
Another reason is that this sort of organizational structure facilitates part of the habit (drummed into me by years of dealing with source-control systems that weren't as smart as Git is) of keeping things in neat spaces, and alphabetical order whenever possible. If you've used SVN, or a version of SourceGear Vault like the one I managed for a while, you're maybe already nodding in sympathy.
Enough. Here's what my module template looks like:
#!/usr/bin/env python
"""TODO: Document the module:
Provides classes and functionality relating to XXXX."""
#-----------------------------------#
# Standard-library imports. #
#-----------------------------------#
# Uncomment this if there are any interfaces or abstract classes here.
# import abc
# Need to import sys in order to add the idic library path!
import sys
#-----------------------------------#
# Imports of other third-party #
# libraries and functionality. #
#-----------------------------------#
#-----------------------------------#
# idic-library imports. #
#-----------------------------------#
sys.path.insert( 1, '/usr/local/lib/idic' )
from doc_metadata import describe
# Import documentation-metadata functionality
from doc_metadata import describe
#-----------------------------------#
# File metadata #
#-----------------------------------#
__author__ = 'Author Name'
__version__ = 'Version of File'
__copyright__ = 'Copyright Statement'
__license__ = 'License Info'
__credits__ = ['Author Name', 'Contributor Name']
__maintainer__ = 'Maintainer Name'
__email__ = 'Email to contact Maintainer'
__status__ = 'Status of file'
#-----------------------------------#
# Create an __all__ list to support #
# "from spam import eggs" syntax. #
#-----------------------------------#
__all__ = []
#-----------------------------------#
# Initialization that needs to #
# happen before member definition. #
#-----------------------------------#
#-----------------------------------#
# Defined constants. #
#-----------------------------------#
#-----------------------------------#
# Defined exceptions. #
#-----------------------------------#
#-----------------------------------#
# Defined functions. #
#-----------------------------------#
#-----------------------------------#
# Defined class-interfaces. #
#-----------------------------------#
#-----------------------------------#
# Defined abstract classes. #
#-----------------------------------#
#-----------------------------------#
# Defined concrete classes. #
#-----------------------------------#
#-----------------------------------#
# Imports to resolve circular #
# dependencies. Avoid if possible. #
#-----------------------------------#
#-----------------------------------#
# Initialization that needs to #
# happen after member definition. #
#-----------------------------------#
#-----------------------------------#
# Code to execute if file is called #
# or run directly. #
#-----------------------------------#
if __name__ == '__main__':
pass
Working from top to bottom, here's what it provides:
- A standard
shebang
and module doc-string: #!/usr/bin/env python """TODO: Document the module: Provides classes and functionality relating to XXXX."""
- A section for standard library imports
- These are imports from the main Python installation on the machine
- A section for importing other third-party functionality
- I've never (knowingly) used this, but if there are
other
modules/packages, or imports from them, that aren't part of the standard Python distribution, this would be the place to import them. - Set-up and import of my own libraries
#-----------------------------------# # idic-library imports. # #-----------------------------------# sys.path.insert( 1, '/usr/local/lib/idic' ) from doc_metadata import describe # Import documentation-metadata functionality from doc_metadata import describe
- Note that the path being added matches the one in the project-structure
from my previous post after it's been deployed.
Prior to deployment, resolution of the path may have to be
set up in the editor/IDE. I know that setting a
PYTHONPATH
in Geany's project-properties takes care of allowing the F5 execution-command to work, just like it would for a command-line execution: - File meta-data:
#-----------------------------------# # File metadata # #-----------------------------------# __author__ = 'Author Name' __version__ = 'Version of File' __copyright__ = 'Copyright Statement' __license__ = 'License Info' __credits__ = ['Author Name', 'Contributor Name'] __maintainer__ = 'Maintainer Name' __email__ = 'Email to contact Maintainer' __status__ = 'Status of file'
- An explicit declaration of
__all__
- This allows the members of the module to be imported with the
from [module] import [*|name[, name,...]]
syntax. - A set of sections for specific type of constructs and processes
- From
Initialization that needs to happen before member definition
throughInitialization that needs to happen after member definition.
- Definitions of package-level constants, functions, interfaces, abstract classes, and concrete classes are all encompassed in these sections.
- The
circular imports
section may take some explaining, and I don't want to clutter this page with it just now. I hope that I wont actually encounter it, but the section is there anyway, just in case... - Finally — any code that should be run if the module itself is executed
#-----------------------------------# # Code to execute if file is called # # or run directly. # #-----------------------------------# if __name__ == '__main__': pass
- I frequently use this section to write small chunks of test-code as I'm working through the functionality of a module.
My Package Template
Structurally, the template-file for a package-header file is almost
identical to the one for a module — The only difference is near
the end of the file, where there is a space intended for adding related
packages by appending them to __all__
:
#-----------------------------------#
# Child modules and packages. #
#-----------------------------------#
#-----------------------------------#
# Code to execute if file is called #
# or run directly. #
#-----------------------------------#
if __name__ == '__main__':
pass
That, plus the file being saved as __init__.py
in its parent
directory are the only differences between modules and package-header files as far
as these templates are concerned.
Short, sweet, and to the point, I hope. Next time around, I'll start diving in to the templates I have set up for defining classes.
No comments:
Post a Comment