Custom namespaces

3 views
Skip to first unread message

Steven D'Aprano

unread,
Aug 1, 2009, 9:06:47 PM8/1/09
to
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__:

>>> import __main__
>>> __main__.__dict__ = MyNamespace()
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:

>>> __main__.__dict__.__class__ = MyNamespace
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?

>>> class MyNamespace(dict):
... 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'
1
>>> C = new.classobj("C", (object,), namespace)
>>> C.x
1

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:

>>> namespace
{'y': 2, 'x': 1, '__module__': '__main__', 'z': 3, '__doc__': None}


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

--
Steven

Chris Rebert

unread,
Aug 2, 2009, 12:46:35 AM8/2/09
to Steven D'Aprano, pytho...@python.org
On Sat, Aug 1, 2009 at 6:06 PM, Steven
D'Aprano<st...@remove-this-cybersource.com.au> wrote:
> 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__:
>
>>>> import __main__
>>>> __main__.__dict__ = MyNamespace()
> 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:
>
>>>> __main__.__dict__.__class__ = MyNamespace
> 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?
<snip>

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

> 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
--
http://blog.rebertia.com

Steven D'Aprano

unread,
Aug 2, 2009, 3:18:53 AM8/2/09
to
On Sat, 01 Aug 2009 21:46:35 -0700, Chris Rebert wrote:

>> 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/

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))

--
Steven

Chris Rebert

unread,
Aug 2, 2009, 3:31:05 AM8/2/09
to Steven D'Aprano, pytho...@python.org
On Sun, Aug 2, 2009 at 12:18 AM, Steven
D'Aprano<st...@remove-this-cybersource.com.au> wrote:
> On Sat, 01 Aug 2009 21:46:35 -0700, Chris Rebert wrote:
>
>>> 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/
>
> 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.

Michele Simionato

unread,
Aug 6, 2009, 11:29:35 PM8/6/09
to
On Aug 2, 6:46 am, Chris Rebert <c...@rebertia.com> wrote:
> > 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/

Here is an example of usage:

http://www.artima.com/weblogs/viewpost.jsp?thread=236234
http://www.artima.com/weblogs/viewpost.jsp?thread=236260
(yes, it only works for Python 3+)

Reply all
Reply to author
Forward
0 new messages