Is it a good practice to add names to __all__ using a decorator?
Is this a good practice in Python (from Active State Recipes -- Public Decorator)?
import sys
def pu开发者_StackOverflowblic(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
The general idea would be to define a decorator that takes a function or class
and adds its name to the __all__
of the current module.
The more idiomatic way to do this in Python is to mark the private functions as private by starting their name with an underscore:
def public(x):
...
def _private_helper(y):
...
More people will be familiar with this style (which is also supported by the language: _private_helper
will not be exported even if you do not use __all__
) than with your public
decorator.
Yes, it's a good practice. This decorator allows you to state your intentions right at function or class definition, rather than directly afterwards. That makes your code more readable.
@public
def foo():
pass
@public
class bar():
pass
class helper(): # not part of the modules public interface!
pass
Note: helper
is still accessible to a user of the module by modulename.helper
. It's just not imported with from modulename import *
.
I think the question is a bit subjective, but I like the idea. I usually use __all__
in my modules but I sometimes forget to add a new function that I intended to be part of the public interface of the module. Since I usually import modules by name and not by wildcards, I don't notice the error until someone else in my team (who uses the wildcard syntax to import the entire public interface of a module) starts to complain.
Note: the title of the question is misleading as others have already noticed among the answers.
This doesn't automatically add names to __all__
, it simply allows you to add a function to all by decorating it with @public
. Seems like a nice idea to me.
精彩评论