Namespace hack


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!
 
Ad

Advertisements

S

Steven D'Aprano

Pardon me for breaking threading, but Daniel's response is not available
on my ISP's news server, and I only discovered it by accident.

Namespaces are one honking great idea -- let's do more of those!
[...]

Funny, you got to the last line of "import this" but apparently
skipped the second line:

Explicit is better than implicit.

And you didn't even post your message on April 1 so no, I can't laugh
even though I'd like to.

Do you object to the ability to write standard Python modules?

# module.py
def spam(obj, n):
return len(obj) + n

def ham(obj):
return spam(obj, 23)


By your apparent misunderstanding of the Zen, you think that this should
be written with oodles of more explicitness, 'cos explicit is always
better, right?

keyword.def globals.spam(locals.obj, locals.n):
keyword.return builtin.len(locals.obj) + locals.n

keyword.def globals.ham(locals.obj):
keyword.return globals.spam(locals.obj, 23)


Python, like most (all?) non-trivial languages, has scoping rules so that
you can refer to names without explicitly specifying which namespace they
are in. So long as this is unambiguous, Explicit vs Implicit is
irrelevant if not outright wrong.

My namespace decorator simply applies a slightly different set of scoping
rules to the ones you are already used to in modules. It's no worse than
nested functions (hardly a surprise, because it is built on nested
functions!) or module-level scoping rules.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top