Welcome, guest | Sign In | My Account | Store | Cart

The DRY principle says, "Don't repeat yourself". A Python module typically defines a global variable named "__all__" that holds the names of everything the author wants visible. This means you have to type each function or class name a second time, and you have to maintain the contents of __all__ manually. This fixes that.

Python, 15 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import sys

def public(f):
    """"Use a decorator to avoid retyping function/class names.

    * Based on an idea by Duncan Booth:
    http://groups.google.com/group/comp.lang.python/msg/11cbb03e09611b8a
    * Improved via a suggestion by Dave Angel:
    http://groups.google.com/group/comp.lang.python/msg/3d400fb22d8a42e1
    """
    all = sys.modules[f.__module__].__dict__.setdefault('__all__', [])
    if f.__name__ not in all:  # Prevent duplicates if run from an IDE.
        all.append(f.__name__)
    return f
public(public)  # Emulate decorating ourself

I've seen two techniques for exporting variables. One is to have a simple assignment somewhere (usually at the beginning or end of the module): __all__ = [ 'foo', 'bar' ]

This separates the exportation from the item's definition, so other people do this: __all__ = [] ... def foo(...): ... __all__.append('foo') class bar(...): ... __all__.append('bar')

This is better, but it still puts the code at the bottom of the item's declaration.

My solution is this:

import public from my_utilites

@public def foo(...): ...

@public class bar(...): ...

2 comments

Tim Vieira 11 years, 11 months ago  # | flag

... or you can follow underscore conventions. Only variables which are NOT prefixed with and underscore are included in __all__ (unless you override it). Meaning, rather than use a decorator to "hide" members of a module's namespace, you can put and underscore at the beginning of the name.

Sam Denton (author) 11 years, 11 months ago  # | flag

Quoting from (An Unofficial) Python Reference Wiki: "__all__ should contain the entire public API. It is intended to avoid accidentally exporting items that are not part of the API (such as library modules which were imported and used within the module)."