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

_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to