Python¶
The general rule when writing Python code is to follow PEP 8. The rules given later in this document override what is said in PEP 8.
Be tolerant of code that doesn’t follow these conventions: our code base has been evolving over years and doesn’t always match the current style as we update these rules. Also, we want to reuse software written for other projects that do not adhere to our rules.
Remember that PEP 8 explicitly allows breaking a rule in the interest of keeping code consistent.
A reasonable goal is that code covered by the ZPL should follow these conventions.
License statement, module docstring¶
Python files should always contain the most current license comment at the top followed by the module documentation string.
Here is the template:
##############################################################################
#
# Copyright (c) 2016 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""One-line summary goes here.
Module documentation goes here.
"""
Whitespace¶
Trailing whitespace should not occur, nor should multiple blank lines at the end of files.
Import statements¶
All imports should be at the top of the module, after the module docstring and/or comments, but before module globals.
It is sometimes necessary to violate this to address circular import problems. If this is the case, add a comment to the import section at the top of the file to flag that this was done.
Refrain from using relative imports. Instead of:
import .foo # from same package
you can write:
from zope.package.module import foo
Attribute and method names¶
The naming of attributes as recommended by PEP 8 is controversial. PEP 8
prefers attribute_name
over attributeName
. Newer code tends to
prefer the use of underscores over camel case. However, Zope has been
built originally with the latter rule and a lot of code still use this
scheme.
Boolean-type attributes should always form a true-false-question,
typically using “has” or “is” as prefix. Example: is_required
instead
of required
.
Method names should always start with a verb that describes the action.
Examples:
good:
first_name
is_required
execute_command()
save()
convert_value_to_string()
bad:
FirstName
required
command()
string()
Local variables¶
Single-letter variable names should be avoided unless:
Their meaning is extremely obvious from the context, and
Brevity is desirable
The most obvious case for single-letter variables is for iteration variables.
try
/except
blocks¶
try
blocks should cover as little code as possible. except
statements should match exceptions as specific as possible.
For example, if you are converting a value to an int
, and you want
to catch conversion errors, you need only catch ValueError
. Be sure
to do the minimum possible between your try:
and except
ValueError:
statements:
try:
int(x)
except ValueError:
...
String handling¶
Use startswith
and endswith
because it is faster, cleaner and less
error-prone than comparing sliced strings:
# Yes:
if foo.startswith('bar'):
...
if foo.endswith('.html'):
...
# No:
if foo[:3]=='bar':
...
if foo[-5:]=='.html':
...
Type checks¶
Constructs like if type(obj) is type('')
should be replaced using
isinstance()
:
# Yes:
if isinstance(obj, int):
...
# No:
if type(obj) is type(1):
...
if type(obj) is int:
Marker objects¶
Use instances of object
if you need to construct marker objects (for
example when detecting default values). Compare them using is
as
recommended by PEP 8.
Interfaces¶
Interface names adhere to PEP 8’s naming of classes, except that they
are prefixed with a capital I
, as in IMagicThing
.
One function of interfaces is to document functionality, so be very verbose with the documentation strings.
All public interfaces should go into a file called interfaces.py
.
“Public” interfaces are those that you expect to be implemented more
than once. Interfaces that are likely to be implemented only once, like
IGlobalAdapterService
, should live in the same module as their
implementation.