assigning a custom mapping type to __dict__

Discussion in 'Python' started by Steven Bethard, Mar 1, 2005.

  1. I tried to Google for past discussion on this topic, but without much
    luck. If this has been discussed before, I'd be grateful for a pointer.

    Does anyone know why you can't assign a custom mapping type to an
    object's __dict__?

    py> class M(object):
    .... def __getitem__(self, key):
    .... return 42
    .... def __setitem__(self, key, value):
    .... pass
    ....
    py> class C(object):
    .... pass
    ....
    py> c = C()
    py> c.__dict__ = M()
    Traceback (most recent call last):
    File "<interactive input>", line 1, in ?
    TypeError: __dict__ must be set to a dictionary

    I looked at the source in typeobject.c (where this error originates),
    but I'm not fluent enough in CPython yet to be able to tell why a true
    dict type is preferred here over just a mapping type...

    STeVe
    Steven Bethard, Mar 1, 2005
    #1
    1. Advertising

  2. Steven Bethard

    Daniel Cer Guest

    Why not just inherit from dict? That seems to work.

    >>> class M(dict):

    .... def __getitem__(self,key):
    .... return 42
    .... def __setitem__(self,key,value):
    .... pass
    ....
    >>> class C(object):

    .... pass
    ....
    >>> c = C()
    >>> c.__dict__ = M()
    >>> c.__dict__['x']

    42

    -Dan

    Steven Bethard wrote:

    > I tried to Google for past discussion on this topic, but without much
    > luck. If this has been discussed before, I'd be grateful for a pointer.
    >
    > Does anyone know why you can't assign a custom mapping type to an
    > object's __dict__?
    >
    > py> class M(object):
    > ... def __getitem__(self, key):
    > ... return 42
    > ... def __setitem__(self, key, value):
    > ... pass
    > ...
    > py> class C(object):
    > ... pass
    > ...
    > py> c = C()
    > py> c.__dict__ = M()
    > Traceback (most recent call last):
    > File "<interactive input>", line 1, in ?
    > TypeError: __dict__ must be set to a dictionary
    >
    > I looked at the source in typeobject.c (where this error originates),
    > but I'm not fluent enough in CPython yet to be able to tell why a true
    > dict type is preferred here over just a mapping type...
    >
    > STeVe
    Daniel Cer, Mar 1, 2005
    #2
    1. Advertising

  3. Steven Bethard

    Nick Coghlan Guest

    Daniel Cer wrote:
    > Why not just inherit from dict? That seems to work.


    Because that isn't the question - Steven knows how to make it work, what he's
    curious about is why things are the way they are :)

    Anyway, a quick look suggests that it is due to typeobject.c using the concrete
    PyDict_* API calls [1] to manipulate tp_dict, rather than the abstract
    PyMapping_* calls [2]. The reason behind using the concrete API is, presumably,
    a question of speed :)

    Cheers,
    Nick.

    [1] http://www.python.org/dev/doc/devel/api/dictObjects.html
    [2] http://www.python.org/dev/doc/devel/api/mapping.html
    --
    Nick Coghlan | | Brisbane, Australia
    ---------------------------------------------------------------
    http://boredomandlaziness.skystorm.net
    Nick Coghlan, Mar 1, 2005
    #3
  4. Steven Bethard

    Duncan Booth Guest

    Daniel Cer wrote:

    > Why not just inherit from dict? That seems to work.
    >
    > >>> class M(dict):

    > ... def __getitem__(self,key):
    > ... return 42
    > ... def __setitem__(self,key,value):
    > ... pass
    > ...
    > >>> class C(object):

    > ... pass
    > ...
    > >>> c = C()
    > >>> c.__dict__ = M()
    > >>> c.__dict__['x']

    > 42
    >


    Didn't test this very much, did you?

    >>> c.x


    Traceback (most recent call last):
    File "<pyshell#23>", line 1, in -toplevel-
    c.x
    AttributeError: 'C' object has no attribute 'x'

    Or even:

    >>> c = C()
    >>> c.__dict__ = M({'x': 1})
    >>> c.x

    1
    >>> c.__dict__['x']

    42
    >>>
    Duncan Booth, Mar 1, 2005
    #4
  5. Steven Bethard

    Daniel Cer Guest

    > > Why not just inherit from dict? That seems to work.
    >
    > Because that isn't the question - Steven knows how to make it work, what he's
    > curious about is why things are the way they are :)


    Sorry, didn't mean to be a pest :)

    I guess I assumed Steve already knew that he could inherit from dict.
    That being said, I was wondering why pragmatically this wouldn't be the
    right thing to do (in order to do what he seemed to want to do).

    <me> braces self for the true but not always too informative response of
    'in principle, it's best to use the most abstract interface possible'</me>

    -Dan


    >
    > Anyway, a quick look suggests that it is due to typeobject.c using the concrete
    > PyDict_* API calls [1] to manipulate tp_dict, rather than the abstract
    > PyMapping_* calls [2]. The reason behind using the concrete API is, presumably,
    > a question of speed :)
    >
    > Cheers,
    > Nick.
    >
    > [1] http://www.python.org/dev/doc/devel/api/dictObjects.html
    > [2] http://www.python.org/dev/doc/devel/api/mapping.html
    > --
    > Nick Coghlan | | Brisbane, Australia
    > ---------------------------------------------------------------
    > http://boredomandlaziness.skystorm.net
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >
    Daniel Cer, Mar 1, 2005
    #5
  6. Daniel Cer wrote:
    >>>Why not just inherit from dict? That seems to work.

    >>
    >>Because that isn't the question - Steven knows how to make it work, what he's
    >>curious about is why things are the way they are :)

    >
    > Sorry, didn't mean to be a pest :)
    >
    > I guess I assumed Steve already knew that he could inherit from dict.
    > That being said, I was wondering why pragmatically this wouldn't be the
    > right thing to do (in order to do what he seemed to want to do).


    The problem with inheriting from dict is that you then need to override
    *all* the methods in the dict object, because they all go straight to
    Python's dict'c C code functions. So just because you redefine
    __getitem__ doesn't mean you don't still have to redefine __contains__,
    get, update, etc. UserDict.DictMixin can help with this some, but the
    ideal situation would be to only have to define the methods you actually
    support. Inheriting from dict likely means you have to redefine a bunch
    of functions to raise Exceptions saying that they're unsupported.

    STeVe
    Steven Bethard, Mar 1, 2005
    #6
  7. Steven Bethard

    Nick Coghlan Guest

    Steven Bethard wrote:
    > The problem with inheriting from dict is that you then need to override
    > *all* the methods in the dict object, because they all go straight to
    > Python's dict'c C code functions. So just because you redefine
    > __getitem__ doesn't mean you don't still have to redefine __contains__,
    > get, update, etc. UserDict.DictMixin can help with this some, but the
    > ideal situation would be to only have to define the methods you actually
    > support. Inheriting from dict likely means you have to redefine a bunch
    > of functions to raise Exceptions saying that they're unsupported.


    You're just lucky the affected class is already overriding __getattribute__, so
    the __dict__ is generally getting accessed from Python code :)

    If it weren't for that, object.c's direct calls to the PyDict_* API would be
    making things even more fun for you than they already are (as Duncan pointed out).

    Cheers,
    Nick.

    --
    Nick Coghlan | | Brisbane, Australia
    ---------------------------------------------------------------
    http://boredomandlaziness.skystorm.net
    Nick Coghlan, Mar 2, 2005
    #7
  8. Steven Bethard

    Nick Coghlan Guest

    Steven Bethard wrote:
    > support. Inheriting from dict likely means you have to redefine a bunch
    > of functions to raise Exceptions saying that they're unsupported.


    Hmm. . .

    We've got the NotImplemented singleton already to let special methods say "I
    thought I might be able to handle this, but I can't".

    Maybe "__op__ = NotImplemented" should clear the associated slot. It would also
    make it easier to inherit from list and handle slices in __getitem__ by writing
    "__getslice__ = NotImplemented" instead of overriding __getslice__ to delegate
    to __getitem__.

    Cheers,
    Nick.

    --
    Nick Coghlan | | Brisbane, Australia
    ---------------------------------------------------------------
    http://boredomandlaziness.skystorm.net
    Nick Coghlan, Mar 2, 2005
    #8
  9. Nick Coghlan wrote:
    > Steven Bethard wrote:
    >
    >> The problem with inheriting from dict is that you then need to
    >> override *all* the methods in the dict object, because they all go
    >> straight to Python's dict'c C code functions. So just because you
    >> redefine __getitem__ doesn't mean you don't still have to redefine
    >> __contains__, get, update, etc. UserDict.DictMixin can help with this
    >> some, but the ideal situation would be to only have to define the
    >> methods you actually support. Inheriting from dict likely means you
    >> have to redefine a bunch of functions to raise Exceptions saying that
    >> they're unsupported.

    >
    >
    > You're just lucky the affected class is already overriding
    > __getattribute__, so the __dict__ is generally getting accessed from
    > Python code :)
    >
    > If it weren't for that, object.c's direct calls to the PyDict_* API
    > would be making things even more fun for you than they already are (as
    > Duncan pointed out).


    Yup, I noticed that. Lucky us. =)

    STeVe
    Steven Bethard, Mar 2, 2005
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ed Young
    Replies:
    4
    Views:
    321
    Ed Young
    Aug 10, 2003
  2. Replies:
    1
    Views:
    326
    Alex Martelli
    Nov 6, 2003
  3. Derek Fountain

    When is a __dict__ not a __dict__?

    Derek Fountain, Apr 21, 2004, in forum: Python
    Replies:
    1
    Views:
    322
    John Roth
    Apr 21, 2004
  4. Lyes Amazouz
    Replies:
    2
    Views:
    272
    Lyes Amazouz
    Aug 20, 2008
  5. weston
    Replies:
    1
    Views:
    238
    Richard Cornford
    Sep 22, 2006
Loading...

Share This Page