3

From the Python 2.7 data model:

A class has a namespace implemented by a dictionary object. Class attribute references are translated to lookups in this dictionary, e.g., C.x is translated to C.__dict__["x"] (although for new-style classes in particular there are a number of hooks which allow for other means of locating attributes).

OK, so if I do this:

class SpecialDict(object):
   ... special logic ...

class SomeClass(object):
   def _asdict(self):
     return SpecialDict(self)

   __dict__ = property(_asdict)

what mapping methods or other magic methods that mimic container types need to be present in SpecialDict? Is it just __getitem__ or are there others?

The SomeClass here is simplified from another question I had, reproduced here just so this question stands alone:

from collections import OrderedDict
from operator import itemgetter as _itemgetter

class Foo(tuple):
    __slots__ = ()
    _fields = ('foo',)
    _nargs = 1
    _repr_format = '(foo=%r)'
    foo = property(_itemgetter(0), doc='Alias for field number 0')

    def __new__(_cls, foo):
        return tuple.__new__(_cls, (foo,))
    @classmethod
    def _make(cls, iterable, new=tuple.__new__, len=len):
        'Make a new Foo object from a sequence or iterable'
        result = new(cls, iterable)
        if len(result) != cls._nargs:
            raise TypeError('Expected 1 argument, got %d' % len(result))
        return result

    def _replace(self, **kwds):
        'Return a new {typename} object replacing specified fields with new values'
        result = self._make(map(kwds.pop, self._fields, self))
        if kwds:
            raise ValueError('Got unexpected field names: %r' % kwds.keys())
        return result

    def __repr__(self):
        'Return a nicely formatted representation string'
        return self.__class__.__name__ + self._repr_format % self

    def _asdict(self):
        'Return a new OrderedDict which maps field names to their values.'
        return OrderedDict(zip(self._fields, self))

    __dict__ = property(_asdict)

    def __getstate__(self):
        'Exclude the OrderedDict from pickling'
        pass

    @property
    def antifoo(self):
        return -self.foo

class Bar(Foo):
    _fields = ('foo','bar')
    _nargs = 2
    _repr_format = '(foo=%r, bar=%r)'
    bar = property(_itemgetter(1), doc='Alias for field number 1')

    def __new__(_cls, foo, bar):
        return tuple.__new__(_cls, (foo, bar))

    @property
    def inversebar(self):
        return 1.0/self.bar
Community
  • 1
  • 1
Jason S
  • 184,598
  • 164
  • 608
  • 970
  • whatever the magic Python hooks use from `__dict__`; if you're not sure of this then you probably can't help me. – Jason S Feb 02 '17 at 22:56
  • 2
    Related: http://stackoverflow.com/q/40667093/674039 – wim Feb 02 '17 at 22:57
  • If you just want to implement attribute access based on key like `obj[key]`. Then you should have a `__getitem__`. If this function raises `KeyError`, then it will call `__missing__` if that is defined within your class *(this part is optional)* – Moinuddin Quadri Feb 02 '17 at 22:58
  • 2
    You can't actually set `__dict__` like that - it'll be ignored. If you want a class to use a special `__dict__`, you'll need to use a metaclass. – user2357112 Feb 02 '17 at 22:58
  • And if you want to find out what kind of stuff gets hit, inherit a normal dict, override `__getattr__` to log/print before delegating to `super`. – wim Feb 02 '17 at 23:01
  • @user2357112 -- thanks... the weird part is that I did have `__dict__ = property(_asdict)` and I can't remember where I got the suggestion from; probably another SO question -- I thought I was mimicking what `namedtuple` does. For the record this is doing some stuff in Jython 2.5.3 since namedtuple doesn't exist and neither does OrderedDict. – Jason S Feb 02 '17 at 23:05
  • 2
    @JasonS: `__dict__ = property(_asdict)` customizes how *instances* of the class respond to attempts to look up their `__dict__`. I don't think namedtuple does that any more; it was a bad idea, and it did weird things to pickling. – user2357112 Feb 02 '17 at 23:09
  • ...but I also want to know how it works in Python, so it's not Jython specific. – Jason S Feb 02 '17 at 23:09
  • You can always do `vars(dict)` to get the list of all the functions implemented in `dict` and individually search for significance of each – Moinuddin Quadri Feb 02 '17 at 23:13
  • @user2357112 so am I better to work with metaclasses? I asked [a question earlier](http://stackoverflow.com/questions/41833266/is-there-any-way-to-create-a-python-class-method-that-does-not-pollute-the-attri) and the sense I got was that descriptors are cleaner/safer than getting into metaclasses. – Jason S Feb 02 '17 at 23:16
  • @wim, gonna try your log/print idea now.... – Jason S Feb 02 '17 at 23:17
  • 1
    I'm voting to close this, in favor of a more direct question http://stackoverflow.com/questions/42014207/why-does-python-2-7-namedtuple-implement-dict – Jason S Feb 02 '17 at 23:26
  • OK, closed, since we have the multiple target feature now. (and upvoted - welcome to 100k, enjoy yr swag!) – wim Apr 06 '18 at 03:09

0 Answers0