[Python-ideas] Enhancing vars()

Terry Reedy tjreedy at udel.edu
Mon Dec 12 21:21:02 EST 2016


On 12/12/2016 6:45 PM, Steven D'Aprano wrote:
> In general, directly accessing dunders is a bit of a code smell. (I
> exclude writing dunder methods in your classes, of course.) There's
> usually a built-in or similar to do the job for you, e.g. instead of
> iterator.__next__() we should use next(iterator).
>
> One of the lesser-known ones is vars(obj), which should be used in place
> of obj.__dict__.
>
> Unfortunately, vars() is less useful than it might be, since not all
> objects have a __dict__. Some objects have __slots__ instead, or even
> both. That is considered an implementation detail of the object.
>
> Proposal: enhance vars() to return a proxy to the object namespace,
> regardless of whether said namespace is __dict__ itself, or a number of
> __slots__, or both. Here is a woefully incompete and untested prototype:

+1  I believe this was mentioned as a possibility on some issue , but I 
cannot find it.  Does vars currently work for things with dict proxies 
instead of dicts?

> class VarsProxy(object):
>     def __init__(self, obj):
>         if not (hasattr(obj, '__dict__') or hasattr(obj, '__slots__')):
>             raise TypeError('object has no namespace')
>         self._obj = obj
>
>     def __getitem__(self, key):
>         slots = getattr(type(self), '__slots__', None)
>         # see inspect.getattr__static for a more correct implementation
>         if slots is not None and key in slots:
>             # return the content of the slot, without any inheritance.
>             return getattr(self._obj, key)
>         else:
>             return self._obj.__dict__[key]
>
>     def __setitem__(self, key, value): ...
>     def __delitem__(self, key): ...
>
>
>
> One complication: it is possible for the slot and the __dict__ to
> both contain the key. In 3.5 that ambiguity is resolved in favour of the
> slot:
>
> py> class X:
> ...     __slots__ = ['spam', '__dict__']
> ...     def __init__(self):
> ...             self.spam = 'slot'
> ...             self.__dict__['spam'] = 'dict'
> ...
> py> x = X()
> py> x.spam
> 'slot'
>
>
> Although __slots__ are uncommon, this would clearly distinguish
> vars(obj) from obj.__dict__ and strongly encourage the use of vars()
> over direct access to the dunder attribute.
>
>
> Thoughts?
>
>
>


-- 
Terry Jan Reedy



More information about the Python-ideas mailing list