From e1f31edcf275b3f3a82c2a05a81d81da984156e4 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Mon, 15 Jul 2013 10:04:57 +0200 Subject: [PATCH] Version of my super getattr hook proposal as posted to python-dev. This will likely see significant changes based on feedback from Steve Dower. --- pep-0447.txt | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 pep-0447.txt diff --git a/pep-0447.txt b/pep-0447.txt new file mode 100644 index 000000000..e43a2317a --- /dev/null +++ b/pep-0447.txt @@ -0,0 +1,161 @@ +PEP: 447 +Title: Hooking into super attribute resolution +Version: $Revision$ +Last-Modified: $Date$ +Author: Ronald Oussoren +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 12-Jun-2013 +Post-History: 2-Jul-2013, ? + + +Abstract +======== + +In current python releases the attribute resolution of the `super class`_ +peeks in the ``__dict__`` attribute of classes on the MRO to look +for attributes. This PEP introduces a hook that classes can use +to override that behavior for specific classes. + + +Rationale +========= + +Peeking in the class ``__dict__`` works for regular classes, but can +cause problems when a class dynamicly looks up attributes in a +``__getattribute__`` method. + +The new hook makes it possible to introduce the same customization for +attribute lookup through the `super class`_. + + +The superclass attribute lookup hook +==================================== + +In C code +--------- + +A new slot ``tp_getattro_super`` is added to the ``PyTypeObject`` struct. The +``tp_getattro`` slot for super will call this slot when it is not ``NULL``, +and will raise an exception when it is not set (which shouldn't happen because +the method is implemented for :class:`object`). + +The slot has the following prototype:: + + PyObject* (*getattrosuperfunc)(PyTypeObject* cls, PyObject* name, + PyObject* object, PyObject* owner); + +The function should perform attribute lookup on *object* for *name*, but only +looking in type *tp* (which will be one of the types on the MRO for *self*) +and without looking in the instance *__dict__*. + +The function returns ``NULL`` when the attribute cannot be found, and raises and +exception. Exception other than ``AttributeError`` will cause failure of super's +attribute resolution. + +The implementation of the slot for the :class:`object` type is +``PyObject_GenericGetAttrSuper``, which peeks in the ``tp_dict`` for *cls*. + +Note that *owner* and *object* will be the same object when using a +class-mode super. + + +In Python code +-------------- + +A Python class can contain a definition for a static method +``__getattribute_super__`` with the following prototype:: + + def __getattribute_super__(cls, name, object, owner): pass + +The method should perform attribute lookup for *name* on instance *self* while +only looking at *cls* (it should not look in super classes or the instance +*__dict__* + +XXX: I haven't got a clue at the moment if the method should be an +instance-, class- or staticmethod. The prototype uses a staticmethod. + +XXX: My prototype automagicly makes this a static method, just like __new__ is +made into a static method. That's more convenient, but also (too?) magical. + +XXX: Should this raise AttributeError or return a magic value to signal that +an attribute cannot be found (such as NotImplemented, used in the comparison +operators)? I'm currently using an exception, a magical return value would +be slightly more efficient because the exception machinery is not invoked. + + +Alternative proposals +--------------------- + +Reuse ``tp_getattro`` +..................... + +It would be nice to avoid adding a new slot, thus keeping the API simpler and +easier to understand. A comment on `Issue 18181`_ asked about reusing the +``tp_getattro`` slot, that is super could call the ``tp_getattro`` slot of all +methods along the MRO. + +AFAIK that won't work because ``tp_getattro`` will look in the instance +``__dict__`` before it tries to resolve attributes using classes in the MRO. +This would mean that using ``tp_getattro`` instead of peeking the class +dictionaries changes the semantics of the `super class`_. + + +Open Issues +=========== + +* The names of the new slot and magic method are far from settled. + +* I'm not too happy with the prototype for the new hook. + +* Should ``__getattribute_super__`` be a class method instead? + + -> Yes? The method looks up a named attribute name of an object in + a specific class. Is also likely needed to deal with @classmethod + and super(Class, Class) + +* Should ``__getattribute_super__`` be defined on object? + + -> Yes: makes it easier to delegate to the default implementation + +* This doesn't necessarily work for class method super class + (e.g. super(object, object))... + + +References +========== + +* `Issue 18181`_ contains a prototype implementation + + The prototype uses different names than this proposal. + + +Copyright +========= + +This document has been placed in the public domain. + +.. _`Issue 18181`: http://bugs.python.org/issue18181 + +.. _`super class`: http://docs.python.org/3/library/functions.html?highlight=super#super + +Changes +======= + +* 3-jul-2013: + + + added note question about having object.__getattribute_super__ + + + added note about class super (super(Cls, Cls).classmethod) + + + changed to API for the python and C functions: + + - argument order + + - now a class method + + - added 'owner' argument (same as object.__get__) + + + added PyObject_GenericGetAttroSuper +