S
Steven D'Aprano
From the Zen of Python ("import this"):
Namespaces are one honking great idea -- let's do more of those!
Inspired by this, I have a decorator that abuses function closures to
create a namespace type with the following properties:
- all methods are static methods that do not take a "self" parameter;
- methods can see "class variables";
- external callers can see selected methods and attributes.
An example may make this clearer.
In a regular class:
class C:
x = 42
def spam(self, y):
return self.x + y
def ham(self, z):
return self.spam(z+1)
Notice that the class attribute x is visible to the outside caller, but
methods spam and ham cannot see it except by prefixing it with a
reference to "self".
Here's an example using my namespace hack example:
@namespace
def C(): # Abuse nested functions to make this work.
x = 42
def spam(y):
return x + y
def ham(z):
return spam(z+1)
return (spam, ham) # Need an explicit return to make methods visible.
However, class attribute x is not exposed. You may consider this a
feature, rather than a bug. To expose a class attribute, define it in the
outer function argument list:
@namespace
def C(x=42):
def spam(y):
return x + y
def ham(z):
return spam(z+1)
return (spam, ham)
And in use:
1042
Here's the namespace decorator:
import inspect
def namespace(func):
spec = inspect.getargspec(func)
ns = {'__doc__': func.__doc__}
for name, value in zip(spec.args, spec.defaults or ()):
ns[name] = value
function = type(lambda: None)
exported = func() or ()
try:
len(exported)
except TypeError:
exported = (exported,)
for obj in exported:
if isinstance(obj, function):
ns[obj.__name__] = staticmethod(obj)
else:
raise TypeError('bad export')
Namespace = type(func.__name__, (), ns)
return Namespace()
Have fun!
Namespaces are one honking great idea -- let's do more of those!
Inspired by this, I have a decorator that abuses function closures to
create a namespace type with the following properties:
- all methods are static methods that do not take a "self" parameter;
- methods can see "class variables";
- external callers can see selected methods and attributes.
An example may make this clearer.
In a regular class:
class C:
x = 42
def spam(self, y):
return self.x + y
def ham(self, z):
return self.spam(z+1)
Notice that the class attribute x is visible to the outside caller, but
methods spam and ham cannot see it except by prefixing it with a
reference to "self".
Here's an example using my namespace hack example:
@namespace
def C(): # Abuse nested functions to make this work.
x = 42
def spam(y):
return x + y
def ham(z):
return spam(z+1)
return (spam, ham) # Need an explicit return to make methods visible.
However, class attribute x is not exposed. You may consider this a
feature, rather than a bug. To expose a class attribute, define it in the
outer function argument list:
@namespace
def C(x=42):
def spam(y):
return x + y
def ham(z):
return spam(z+1)
return (spam, ham)
And in use:
1042
Here's the namespace decorator:
import inspect
def namespace(func):
spec = inspect.getargspec(func)
ns = {'__doc__': func.__doc__}
for name, value in zip(spec.args, spec.defaults or ()):
ns[name] = value
function = type(lambda: None)
exported = func() or ()
try:
len(exported)
except TypeError:
exported = (exported,)
for obj in exported:
if isinstance(obj, function):
ns[obj.__name__] = staticmethod(obj)
else:
raise TypeError('bad export')
Namespace = type(func.__name__, (), ns)
return Namespace()
Have fun!