Custom namespaces

  • Thread starter Steven D'Aprano
  • Start date
S

Steven D'Aprano

I was playing around with a custom mapping type, and I wanted to use it
as a namespace, so I tried to use it as my module __dict__:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: readonly attribute

Why is __dict__ made read-only?

I next thought I could change the type of the namespace to my class:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: only for heap types

Drat, foiled again!!!

Okay, if I can't do this at the module level, can I at least install a
custom namespace at the class level?
.... def __getitem__(self, key):
.... print "Looking up key '%s'" % key
.... return super(MyNamespace, self).__getitem__(key)
....
namespace = MyNamespace(x=1, y=2, z=3)
namespace['x']
Looking up key 'x'
11

Apparently not. It looks like the namespace provided to the class
constructor gets copied when the class is made.

Interestingly enough, the namespace argument gets modified *before* it
gets copied, which has an unwanted side-effect:
{'y': 2, 'x': 1, '__module__': '__main__', 'z': 3, '__doc__': None}


Is there any way to install a custom type as a namespace?
 
C

Chris Rebert

I was playing around with a custom mapping type, and I wanted to use it
as a namespace, so I tried to use it as my module __dict__:

Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: readonly attribute

Why is __dict__ made read-only?

I next thought I could change the type of the namespace to my class:

Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: only for heap types

Drat, foiled again!!!

Okay, if I can't do this at the module level, can I at least install a
custom namespace at the class level?
Apparently not. It looks like the namespace provided to the class
constructor gets copied when the class is made.
Is there any way to install a custom type as a namespace?

For classes/objects, yes, using metaclasses.
See the __prepare__() method in PEP 3115:
http://www.python.org/dev/peps/pep-3115/

Cheers,
Chris
 
S

Steven D'Aprano

For classes/objects, yes, using metaclasses. See the __prepare__()
method in PEP 3115: http://www.python.org/dev/peps/pep-3115/

Looks good, but that's Python 3 only, yes?

At least, I can't get the metaclass to change the __dict__ in Python 2.6.
There's obviously no __prepare__ before 3.0, but I tried the following,
and still __dict__ ends up as a regular dict. Am I missing something?


class VerboseDict(dict):
def __getitem__(self, item):
print ("Looking up key '%s'..." % item)
return super(VerboseDict, self).__getitem__(item)

class Meta(type):
def __new__(cls, name, bases, namespace):
namespace = VerboseDict(namespace)
obj = super(Meta, cls).__new__(cls, name, bases, namespace)
return obj

MyClass = Meta('MyClass', (object,), dict(x=1, y=2))
 
C

Chris Rebert

Looks good, but that's Python 3 only, yes?
Correct.

At least, I can't get the metaclass to change the __dict__ in Python 2.6.
There's obviously no __prepare__ before 3.0, but I tried the following,
and still __dict__ ends up as a regular dict. Am I missing something?


class VerboseDict(dict):
   def __getitem__(self, item):
       print ("Looking up key '%s'..." % item)
       return super(VerboseDict, self).__getitem__(item)

class Meta(type):
   def __new__(cls, name, bases, namespace):
       namespace = VerboseDict(namespace)
       obj = super(Meta, cls).__new__(cls, name, bases, namespace)
       return obj

I would /guess/ that type.__new__() is internally doing the equivalent
of dict(namespace). Hence why the addition of __prepare__() was
necessary; it's probably impossible to accomplish what you want in
earlier Python versions.

Cheers,
Chris
 

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

Members online

No members online now.

Forum statistics

Threads
473,992
Messages
2,570,220
Members
46,807
Latest member
ryef

Latest Threads

Top