[Python-Dev] Hooking into super() attribute resolution (original) (raw)
Steve Dower Steve.Dower at microsoft.com
Mon Jul 8 17:19:42 CEST 2013
- Previous message: [Python-Dev] Hooking into super() attribute resolution
- Next message: [Python-Dev] Hooking into super() attribute resolution
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
The only real advantage is a simpler signature and more easily explained use (assuming the person you're explaining it to is familiar with metaclasses, so most of the hard explaining has been done).
I'm still not sure that this isn't simply a bug in super. If the superclass's metaclass provides a getattr then it should probably use it and abandon it's own MRO traversal.
I still haven't thought the edge cases through, and it seems like there'd be some with that change, so that's where getattribute_super comes in - super can call it without abandoning its MRO traversal.
AFAICT, the difference between that and getlocalattribute is that the latter would be implemented on a metaclass while the former takes extra parameters. I think this functionality is advanced enough that requiring a metaclass isn't unreasonable.
(The proxy objects idea was a red herring, sorry :) )
Steve
Sent from my Windows Phone
From: Ronald Oussoren<mailto:ronaldoussoren at mac.com> Sent: 7/7/2013 12:37 To: Steve Dower<mailto:Steve.Dower at microsoft.com> Cc: python-dev at python.org<mailto:python-dev at python.org> Subject: Re: [Python-Dev] Hooking into super() attribute resolution
On 7 Jul, 2013, at 17:17, Steve Dower <Steve.Dower at microsoft.com> wrote:
Could the same result be achieved by hooking the MRO that super uses and returning a list of proxy objects?
What is the advantage over adding a hook to the class itself? That seems to be the right place to add such a hook, super already looks in the classes along the MRO and my proposal would add a formal interface for that instead of having super peek into the class dict. I have thought of using a custom mapping object for the tp_dict slot to intercept this, but that won't work because super assumes that tp_dict is an actual PyDictObject (and likely other parts of the interpreter do so as well).
And then wouldn't you only really need a getattribute that doesn't recurse (getlocalattribute)? The end result may be conceptually simpler, but you've thought through the edge cases better than I have.
getattribute_super already is a kind of getlocalattribute, the primairy difference being getattribute_super is a staticmethod instead of an instance method. To be honest I'm not sure if a staticmethod is the right solution, I'm having a hard time to determine if this should be a class, instance or static method.
Currently super(StartClass, x) basicly does (assuming x is an instance method):
def getattribute(self, name): mro = type(x).mro() idx = mro.index(StartClass) while idx < len(mro): dct = mro[idx].dict try: result = dct[name] # deal with descriptors here return result
except KeyError:
continue
return object.__getattribute__(self, name)
With my proposal 'dct' would no longer be needed and 'result = dct[name]' would be 'mro[idx].getattribute_super(mro[idx], name, x, StartClass)' (I may have the last argument for the call to getattribute_super wrong, but that's the idea). Given that the first argument of get...super is the same as the object the method get getattr-ed from I guess the method should be a classmethod instead of an staticmethod. Changing that would be easy enough.
I'm still interested in feedback on the basic idea, I'd love to here that my proposal isn't necessary because there is already a way to get the behavior I'm looking for although that's nog going to happen ;-).
Ronald
(Apologies for the HTML top-post)
I don't mind.
PS. Does anyone know if the pep editors are away (conferences, holidays, ...)? I could just check in my proposal in the peps repository, but as this is my first PEP I'd prefer to follow the documented procedure and have someone that knows what he's doing look at the metadata before checking in.
Sent from my Windows Phone From: Ronald Oussoren Sent: 7/6/2013 0:47 To: Ronald Oussoren Cc: python-dev at python.org Dev Subject: Re: [Python-Dev] Hooking into super() attribute resolution I've updated the implementation in issue 18181 <http://bugs.python.org/issue18181> while adding some tests, and have updated the proposal as well. The proposal has some open issues at the moment, most important of which is the actual signature for the new special method; in particular I haven't been able to decide if this should be an instance-, class- or static method. It is a static method in the proposal and prototype, but I'm not convinced that that is the right solution. Ronald
PEP: TODO Title: Hooking into super attribute resolution Version: RevisionRevisionRevision Last-Modified: DateDateDate Author: Ronald Oussoren <ronaldoussoren at mac.com> 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 thesuper class
. The superclass attribute lookup hook ==================================== In C code --------- A new slottpgetattrosuper
is added to thePyTypeObject
struct. Thetpgetattro
slot for super will call this slot when it is notNULL
, 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 returnsNULL
when the attribute cannot be found, and raises and exception. Exception other thanAttributeError
will cause failure of super's attribute resolution. The implementation of the slot for the :class:object
type isPyObjectGenericGetAttrSuper
, which peeks in thetpdict
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_getattributesuper_
with the following prototype:: def getattributesuper(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 --------------------- Reusetpgetattro
..................... It would be nice to avoid adding a new slot, thus keeping the API simpler and easier to understand. A comment onIssue 18181
asked about reusing thetpgetattro
slot, that is super could call thetpgetattro
slot of all methods along the MRO. AFAIK that won't work becausetpgetattro
will look in the instance_dict_
before it tries to resolve attributes using classes in the MRO. This would mean that usingtpgetattro
instead of peeking the class dictionaries changes the semantics of thesuper 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_getattributesuper_
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_getattributesuper_
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 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
Python-Dev mailing list Python-Dev at python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/steve.dower%40microsoft.com
Python-Dev mailing list Python-Dev at python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/ronaldoussoren%40mac.com
-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.python.org/pipermail/python-dev/attachments/20130708/ec8c9d0b/attachment.html>
- Previous message: [Python-Dev] Hooking into super() attribute resolution
- Next message: [Python-Dev] Hooking into super() attribute resolution
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]