diff options
author | michele.simionato <devnull@localhost> | 2007-12-02 11:13:11 +0000 |
---|---|---|
committer | michele.simionato <devnull@localhost> | 2007-12-02 11:13:11 +0000 |
commit | 20ce686b0193d67ea56823a30551140f88b3aee1 (patch) | |
tree | 76015e7e4dc0b000bd857a2bdba6fb7976ac29a7 /pypers/super/super.html | |
parent | f08f40335ad7f0ac961f25dabaaed34c4d4bcc44 (diff) | |
download | micheles-20ce686b0193d67ea56823a30551140f88b3aee1.tar.gz |
Commited all py papers into Google code
Diffstat (limited to 'pypers/super/super.html')
-rwxr-xr-x | pypers/super/super.html | 564 |
1 files changed, 564 insertions, 0 deletions
diff --git a/pypers/super/super.html b/pypers/super/super.html new file mode 100755 index 0000000..a970a18 --- /dev/null +++ b/pypers/super/super.html @@ -0,0 +1,564 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +<meta name="generator" content="Docutils 0.3.4: http://docutils.sourceforge.net/" /> +<title>The truth about super</title> +<meta name="author" content="Michele Simionato" /> +<meta name="date" content="June 2004" /> +<link rel="stylesheet" href="default.css" type="text/css" /> +</head> +<body> +<h1 class="title">The truth about <tt class="literal"><span class="pre">super</span></tt></h1> +<table class="docinfo" frame="void" rules="none"> +<col class="docinfo-name" /> +<col class="docinfo-content" /> +<tbody valign="top"> +<tr><th class="docinfo-name">Author:</th> +<td>Michele Simionato</td></tr> +<tr class="field"><th class="docinfo-name">Email:</th><td class="field-body"><a class="reference" href="mailto:michele.simionato@libero.it">michele.simionato@libero.it</a></td> +</tr> +<tr><th class="docinfo-name">Date:</th> +<td>June 2004</td></tr> +<tr><th class="docinfo-name">Status:</th> +<td>Draft</td></tr> +</tbody> +</table> +<div class="document" id="the-truth-about-super"> +<p><tt class="literal"><span class="pre">super</span></tt> is a new built-in, first introduced in Python 2.2 and slightly +improved and fixed in Python 2.3, which is little known to the average +Python programmer. One of the reason for this +fact is its poor documentation`: at the time of this writing +(June 2004) <tt class="literal"><span class="pre">super</span></tt> documentation is incomplete and in some parts +misleading and even wrong. For instance, it was recently pointed out +on comp.lang.python that the standard library (Python 2.3.4, section 2.1) +still says:</p> +<pre class="literal-block"> +super(type[, object-or-type]) + Return the superclass of type. If the second argument is omitted the + super object returned is unbound. If the second argument is an object, + isinstance(obj, type) must be true. If the second argument is a type, + issubclass(type2, type) must be true. super() only works for new-style + classes. +</pre> +<p>The first sentence is just plain wrong. <tt class="literal"><span class="pre">super</span></tt> does not return the +superclass. There is no such a thing as "the" superclass in a Multiple +Inheritance (MI) language. Also, the sentence about 'unbound' is misleading, +since it may easily lead the programmer to think about bound and unbound +methods, whereas it has nothing to do with that concept. Finally, there +subtle pitfalls of <tt class="literal"><span class="pre">super</span></tt> which are not at all mentioned. IMNSHO +<tt class="literal"><span class="pre">super</span></tt> is one of the most trickiest and surprising Python constructs, +so it absolutely needs a document to share light on some of his secrets: +the present article aims to fix the issues with the current documentation, +and tell you the "truth" about <tt class="literal"><span class="pre">super</span></tt>. At least the amount of truth +I have discovered with my experimentations, which is certainly +not the whole truth ;)</p> +<p>Here is the plan: first I will discuss the concept of superclass in +a Multiple Inheritance (MI) world (there is no such a thing as +"the" superclass!); second, I will show that <tt class="literal"><span class="pre">super</span></tt> is a proxy +object, able to dispatch to the right methods/attributes in the +MRO; third,</p> +<p>recall some background on +how the resolution of methods works on how +descriptors work and +(essentially pointing out to the standard references); then +I will discuss the more common invocation of <tt class="literal"><span class="pre">super</span></tt> - +the invocation with two arguments - and finally I will discuss +the most tricky part, i.e. invoking <tt class="literal"><span class="pre">super</span></tt> with just one +argument and I will discuss pitfalls.</p> +<p>Finally, a fair warning: this document is aimed to expert +Pythonistas. It is not for the faint of heart ;)</p> +<div class="section" id="first-truth-there-is-no-superclass-in-a-mi-world"> +<h1><a name="first-truth-there-is-no-superclass-in-a-mi-world">First truth: there is no superclass in a MI world</a></h1> +<p>Readers familiar will single inheritance languages, such as +Java or Smalltalk, will have a clear concept of superclass +in mind. This concept, however, has <em>no useful meaning</em> in Python or in +other Multiple Inheritance languages. This fact was proved to +me by Bjorn Pettersen in a thread on comp.lang.python in May 2003 +(at that time I was mistakenly thinking that one could define a +superclass concept in Python). Consider this example from that +discussion:</p> +<pre class="literal-block"> + +-----+ + | T | + |a = 0| + +-----+ + / \ + / \ ++-------+ +-------+ +| A | | B | +| | | a = 2 | ++-------+ +-------+ + \ / + \ / + +-----+ + | C | + +-----+ + : + : instantiation + c +</pre> +<pre class="doctest-block"> +>>> class T(object): +... a = 0 +</pre> +<pre class="doctest-block"> +>>> class A(T): +... pass +</pre> +<pre class="doctest-block"> +>>> class B(T): +... a = 2 +</pre> +<pre class="doctest-block"> +>>> class C(A,B): +... pass +</pre> +<pre class="doctest-block"> +>>> c = C() +</pre> +<p>Who is the superclass of C? There are two direct superclasses (i.e. bases) +of C: A and B. A comes before B, so one would naturally think +that the superclass of C is A. A inherits the attribute 'a' from T, +so if <tt class="literal"><span class="pre">super(C,c)</span></tt> was returning the superclass of C, then +it should return 'A'. 'A' inherits its attribute 'a' from T, +where 'a' has the value 0, so <tt class="literal"><span class="pre">super(C,c).a</span></tt> would return 0. This +is NOT what happens. Instead, <tt class="literal"><span class="pre">super(C,c).a</span></tt> walks trought the +method resolution order <a class="footnote-reference" href="#id4" id="id1" name="id1">[1]</a> of the class of <tt class="literal"><span class="pre">c</span></tt> (which is 'C') +and retrieves the attribute from the first class above 'C' which +defines it. In this example the MRO of 'C' is [C, A, B, T, object], so +B is the first class above C which defines 'a' and <tt class="literal"><span class="pre">super(C,c).a</span></tt> +correctly returns the value 2, not 0:</p> +<pre class="doctest-block"> +>>> super(C,c).a +2 +</pre> +<p>You may call 'A' the superclass of 'C', but this is not an useful +concept since the methods are resolved by looking at the classes +in the MRO of 'C', and not by looking at the classes in the MRO of A +(which in this case is [A,T, object] and does not contain B).</p> +<p>So, using the word <em>superclass</em> in the standard doc is completely +misleading and should be avoided altogether.</p> +</div> +<div class="section" id="second-truth-super-returns-proxy-objects"> +<h1><a name="second-truth-super-returns-proxy-objects">Second truth: <tt class="literal"><span class="pre">super</span></tt> returns proxy objects</a></h1> +<p>Having understood that <tt class="literal"><span class="pre">super</span></tt> cannot return and does not return the +mythical superclass, we ask ourselves what the hell is returning +<tt class="literal"><span class="pre">super</span></tt> ;) The truth is that <tt class="literal"><span class="pre">super</span></tt> returns proxy objects. +Informally speaking, a proxy object is an object with +the ability to dispatch to methods of other classes via delegation.</p> +<p>Technically, <tt class="literal"><span class="pre">super</span></tt> works by overriding the <tt class="literal"><span class="pre">__getattribute__</span></tt> +method in such a way that its instances becomes proxy objects providing +access to the methods in the MRO. The dispatch is done in such a way +that</p> +<p><tt class="literal"><span class="pre">super(cls,</span> <span class="pre">instance-or-subclass).meth(*args,</span> <span class="pre">**kw)</span></tt></p> +<p>corresponds to</p> +<p><tt class="literal"><span class="pre"><right</span> <span class="pre">method</span> <span class="pre">in</span> <span class="pre">the</span> <span class="pre">MRO>(instance-or-subclass,</span> <span class="pre">*args,</span> <span class="pre">**kw)</span></tt></p> +<p>There is a caveat at this point: the second argument can be +an instance of the first argument, or a subclass of it, but +in <em>both cases</em> a bound method is returned (one could naivily +think, instead, that when a subclass is passed one gets an +unbound method).</p> +<p>For instance, in this example</p> +<pre class="doctest-block"> +>>> class B(object): +... def __repr__(self): +... return "<instance of %s>" % self.__class__.__name__ +</pre> +<pre class="doctest-block"> +>>> class C(B): +... pass +</pre> +<pre class="doctest-block"> +>>> class D(C): +... pass +</pre> +<pre class="doctest-block"> +>>> d = D() +</pre> +<p>both</p> +<pre class="doctest-block"> +>>> print super(C,d).__repr__ +<bound method D.__repr__ of <instance of D>> +</pre> +<p>and</p> +<pre class="doctest-block"> +>>> print super(C,D).__repr__ +<bound method D.__repr__ of <class 'D'>> +</pre> +<p>returns bound methods. This means that when I call those methods, +I get</p> +<pre class="doctest-block"> +>>> print super(C,d).__repr__() +<instance of D> +</pre> +<p>(here d, a D instance is being passed to <tt class="literal"><span class="pre">__repr__</span></tt>) and</p> +<pre class="doctest-block"> +>>> print super(C,D).__repr__() +<instance of type> +</pre> +<p>(here D, an instance of the (meta)class <tt class="literal"><span class="pre">type</span></tt> is being passed +to <tt class="literal"><span class="pre">__repr__</span></tt>).</p> +<p>Reading the docs,one could think that in order to get unbound methods, +she needs to switch to the alternative syntax of <tt class="literal"><span class="pre">super</span></tt>, the single +argument syntax. This is actually completely WRONG.</p> +</div> +<div class="section" id="third-truth-the-unbound-syntax-does-not-access-unbound-methods"> +<h1><a name="third-truth-the-unbound-syntax-does-not-access-unbound-methods">Third truth: the 'unbound' syntax does not access unbound methods</a></h1> +<p>Suppose 'B' has a method called 'meth' like this:</p> +<pre class="doctest-block"> +>>> B.meth = lambda self :'You called B.meth with first argument %s' % self +</pre> +<p>Then <tt class="literal"><span class="pre">B.meth</span></tt> is an unbound method and, mislead by the documentation, +one could expect to be able to access it with the syntax <tt class="literal"><span class="pre">super(C).meth</span></tt>. +This is not the case. You get an error instead:</p> +<pre class="doctest-block"> +>>> super(C).meth +Traceback (most recent call last): + ... +AttributeError: 'super' object has no attribute 'meth' +</pre> +<p>The truth is that unbound super objects cannot be accessed directly, +they must be converted to bound objects in order to make them +to dispatch properly. Unbound super objects can be converted to +bound super objects via the descriptor protocol. For instance, +in this example I can convert <tt class="literal"><span class="pre">super(C)</span></tt> in a super object +bound to the instance 'd' in this way:</p> +<pre class="doctest-block"> +>>> boundsuper = super(C).__get__(d, D) # this is the same as super(C,d) +</pre> +<p>Now I can access the bound method 'd.meth':</p> +<pre class="doctest-block"> +>>> print boundsuper.meth +<bound method D.<lambda> of <instance of D>> +</pre> +<p>To really access the unbound method 'D.meth' is tricky; it could be +done in this way:</p> +<pre class="doctest-block"> +>>> print boundsuper.meth.__get__(None,D) +<unbound method D.<lambda>> +</pre> +<p>All those tricks requires a good grasp of descriptors (see next +paragraph). Here I would like just to point out that in my opinion +having an unbound syntax for descriptors is generating more +confusion than needed. First of all, there is a problem of poor +documentation.</p> +<p>The distinction bound/unbound +can easily be confused with the distinction between bound and unbound +methods. So you could expect <tt class="literal"><span class="pre">super(C).meth</span></tt> to be an unbound method +of the superclass of C (superclass here is intended in some nebolous way). +This is not that dangerous when you get an error; it is much more +dangerous when you don't get an error, but you get a result which is +not what you expect. This happens for special methods which are +already defined in <tt class="literal"><span class="pre">super</span></tt>. +For instance <tt class="literal"><span class="pre">super(C).__repr__</span></tt> does not give any error, +but it is <em>not</em> returning a proxy to <tt class="literal"><span class="pre">D.__repr__</span></tt>, it is +returning <tt class="literal"><span class="pre">super.__repr__</span></tt> bound to the (unbound) super object <tt class="literal"><span class="pre">super(C)</span></tt>:</p> +<pre class="doctest-block"> +>>> print super(C).__repr__() # same as repr(super(C)) +<super: <class 'C'>, NULL> +</pre> +<p>Very tricky. Notice that <tt class="literal"><span class="pre">super</span></tt> also redefines <tt class="literal"><span class="pre">__new__</span></tt>, +<tt class="literal"><span class="pre">__init</span></tt>, <tt class="literal"><span class="pre">__get__</span></tt>, <tt class="literal"><span class="pre">__getattribute</span></tt>, as well as inheriting +other special attributes from <tt class="literal"><span class="pre">object</span></tt>. So you will dispatch to +these methods in <tt class="literal"><span class="pre">super</span></tt> and not to the right methods defined in +the hierarchy at hand. On the other hand, the two-argument syntax +does not have this problem. For instance</p> +<pre class="doctest-block"> +>>> print super(C,C).__repr__() +<instance of type> +</pre> +<p>does the right thing. There is a single use case for the single argument +syntax of <tt class="literal"><span class="pre">super</span></tt> that I am aware of, but I think it gives more troubles +than advantages. The use case is the implementation of "autosuper" made +by Guido on his essay about new-style classes.</p> +<p>The idea there is to use the unbound super objects as private +attributes. For instance, in our example, we could define the +private attribute <tt class="literal"><span class="pre">__sup</span></tt> in the class <tt class="literal"><span class="pre">C</span></tt> as the unbound +super object <tt class="literal"><span class="pre">super(C)</span></tt>:</p> +<pre class="doctest-block"> +>>> C._C__sup = super(C) +</pre> +<p>With this definition inside the methods the syntax +<tt class="literal"><span class="pre">self.__sup.meth(arg)</span></tt> can be used +as an alternative to <tt class="literal"><span class="pre">super(C,</span> <span class="pre">self).meth(arg)</span></tt>, and the advantage is +that you avoid to repeat the name of the class in the calling +syntax, since that name is hidden in the mangling mechanism of +private names. The creation of the <tt class="literal"><span class="pre">__sup</span></tt> attributes can be hidden +in a metaclass and made automatic. So, all this seems to work: but +actually this <em>not</em> the case. +Things may wrong in various case, for instance for classmethods, +as in this example:</p> +<pre class="literal-block"> +#<ex.py> + +class B(object): + def __repr__(self): + return '<instance of %s>' % self.__class__.__name__ + def meth(self): + print "B.meth(%s)" % self + meth = classmethod(meth) + +class C(B): + def meth(self): + print "C.meth(%s)" % self + self.__super.meth() + meth = classmethod(meth) + +C._C__super = super(C) + +class D(C): + pass + +D._D__super = super(D) + + +d=D() + +d.meth() + +#</ex.py> +</pre> +<p>The last line raises an <tt class="literal"><span class="pre">AttributeError:</span> <span class="pre">'super'</span> <span class="pre">object</span> <span class="pre">has</span> <span class="pre">no</span> <span class="pre">attribute</span> +<span class="pre">'meth'.</span></tt></p> +<p>So, using a <tt class="literal"><span class="pre">__super</span></tt> unbound super object is not a robust solution +(notice that everything would work by substituting <tt class="literal"><span class="pre">self.__super.meth()</span></tt> +with <tt class="literal"><span class="pre">super(C,self).meth()</span></tt>. There are other ways to avoid repeating +the class name, see for instance my cookbook recipe.</p> +<p>If it was me, I would just remove the single argument syntax of <tt class="literal"><span class="pre">super</span></tt>, +making it illegal. But this would probably break someone code, so +I don't think it will ever happen. Another solution would be just to +deprecate it. There is no need for this syntax, one can always circumvent it.</p> +</div> +<div class="section" id="forth-truth-super-returns-descriptor-objects"> +<h1><a name="forth-truth-super-returns-descriptor-objects">Forth truth: <tt class="literal"><span class="pre">super</span></tt> returns descriptor objects</a></h1> +<p>Descriptors (more properly I should speak of the descriptor protocol) were +introduced in Python 2.2 by Guido van Rossum. Their primary motivation +is technical, since they were needed to implement the new-style object +system. Descriptors were also used to introduce new standard concepts in +Python, such as classmethods, staticmethods and properties. Moreover, +according to the traditional transparency policy of Python, descriptors +were exposed to the application programmer, giving him/her the freedom +to write custom descriptors. <a class="footnote-reference" href="#id6" id="id2" name="id2">[2]</a> Any serious Python programmer should have +a look at descriptors: luckily they are now very well documented (which was +not the case when I first studied them :-/) thanks to the beautiful essay +of Raimond Hettinger <a class="footnote-reference" href="#id7" id="id3" name="id3">[3]</a>. You should read it before continuing this article, +since it explains all the details. However, for the sake of our discussion +of <tt class="literal"><span class="pre">super</span></tt>, it is enough to say that a <em>descriptor class</em> is just a +regular new-style class which implements a .``__get__`` method with +signature <tt class="literal"><span class="pre">__get__(self,</span> <span class="pre">obj,</span> <span class="pre">objtyp</span> <span class="pre">=</span> <span class="pre">None)</span></tt>. A <em>descriptor object</em> +is just an instance of a descriptor class.</p> +<p>Descriptor objects are intended to be used as attributes (hence their +complete name attribute descriptors). Suppose that 'descr' is a +given descriptor object used as attribute of a given class C. +Then the syntax <tt class="literal"><span class="pre">C.descr</span></tt> is actually implemented by Python as a +call to <tt class="literal"><span class="pre">descr.__get__(None,</span> <span class="pre">C)</span></tt>, whereas the same syntax for an +instance of C corresponds to a call to <tt class="literal"><span class="pre">descr.__get__(c,</span> <span class="pre">type(c))</span></tt>.</p> +<p>This explanation is relevant in order to understand how the <tt class="literal"><span class="pre">super</span></tt> +built-in works when it is called with only one argument, i.e. in the +unbound form. In this case <tt class="literal"><span class="pre">super(C)</span></tt> returns a descriptor which +is intended to be used as an attribute in other classes. This is +an example:</p> +<pre class="doctest-block"> +>>> class D(C): +... sup = super(C) +</pre> +<pre class="doctest-block"> +>>> d = D() +>>> d.sup.a +2 +</pre> +<p>This works since <tt class="literal"><span class="pre">d.sup.a</span></tt> calls</p> +<table class="footnote" frame="void" id="id4" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id1" name="id4">[1]</a></td><td>Descriptors gives an enormous power to the application +programmer, especially when combined with metaclasses. For instance, +using descriptors I did implement a prototype-based object system for +Python in few lines: see of course this was an hack, only useful as proof +of concept.</td></tr> +</tbody> +</table> +</div> +<div class="section" id="fifth-truth-super-does-not-work-with-meta-attributes"> +<h1><a name="fifth-truth-super-does-not-work-with-meta-attributes">Fifth truth: <tt class="literal"><span class="pre">super</span></tt> does not work with meta-attributes</a></h1> +<p>If you start using <tt class="literal"><span class="pre">super</span></tt> intensively, soon or latter you will find +a number of subtilities. One of these is the fact that <tt class="literal"><span class="pre">super</span></tt> does not +work well with the <tt class="literal"><span class="pre">__name__</span></tt> special attribute. Consider this example:</p> +<pre class="doctest-block"> +>>> class B(object): +... "This is class B" +... +>>> class C(B): +... pass +... +</pre> +<p>Here the special class attribute <tt class="literal"><span class="pre">__doc__</span></tt> is retrieved as you would expect:</p> +<pre class="doctest-block"> +>>> super(C,C).__doc__ == super(C,C()).__doc__ == B.__doc__ +True +</pre> +<p>On the other hand, the special attribute <tt class="literal"><span class="pre">__name__</span></tt> is not +retrieved correctly:</p> +<pre class="doctest-block"> +>>> super(C,C).__name__ # one would expect it to be 'B' +Traceback (most recent call last): + File "<stdin>", line 1, in ? +AttributeError: 'super' object has no attribute '__name__' +</pre> +<p>The problem is that <tt class="literal"><span class="pre">__name__</span></tt> is not just a plain class +attribute: it is actually a "getset descriptor" defined on +the metaclass "type" (try to run <tt class="literal"><span class="pre">help(type.__dict__['__name__'])</span></tt> +and you will see for yourself). More in general, <tt class="literal"><span class="pre">super</span></tt> has +problems with meta-attributes, i.e. class attributes of metaclasses. +Meta-attributes differs from regular attributes since they are not +transmitted to the instances of the instances.You can find the +rationale for this behaviour elsewhere <a class="footnote-reference" href="#id8" id="id5" name="id5">[4]</a>: here I am only interested +to the issues with <tt class="literal"><span class="pre">super</span></tt>. Consider this example:</p> +<p>#<example1.py></p> +<dl> +<dt>class M(type):</dt> +<dd>"A metaclass with a class attribute 'a'." +a = 1</dd> +<dt>class B:</dt> +<dd>"An instance of M with a meta-attribute 'a'." +__metaclass__ = M</dd> +<dt>class C(B):</dt> +<dd>"An instance of M with the same meta-attribute 'a'"</dd> +<dt>if __name__ == "__main__":</dt> +<dd>print B.a, C.a # => 1 1 +print super(C,C).a #=> attribute error</dd> +</dl> +<p>#</example1.py></p> +<p>If you run this, you will get an attribute error. This is a case +where <tt class="literal"><span class="pre">super</span></tt> is doing the <em>right</em> thing, since 'a' is <em>not</em> inherited +from B, but it comes directly from the metaclass (again, look at my second +article with David Mertz to understand why it is so), so 'a' +is <em>not</em> in the MRO of C. A similar thing happens for the "__name__" +attribute (the fact that it is a descriptor and not a plain +attribute does not matter), so <tt class="literal"><span class="pre">super</span></tt> is working correctly, but +still it may seems surprising at first.</p> +</div> +<div class="section" id="the-final-truth-there-are-other-bugs-and-pitfalls"> +<h1><a name="the-final-truth-there-are-other-bugs-and-pitfalls">The final truth: there are other bugs and pitfalls</a></h1> +<p>There are various <tt class="literal"><span class="pre">super</span></tt> pitfalls currently undocumented and +that experienced Python programmers should be aware of.</p> +<p>The unbound form of <tt class="literal"><span class="pre">super</span></tt> does not play well with pydoc. +The problems is still there in Python 2.3.4 (see bug report SF729103)</p> +<pre class="doctest-block"> +>>> class B(object): pass +... +>>> class C: +... s=super(B) +... +>>> help(C) +Traceback (most recent call last): + ... + ... lots of stuff here + ... +File "/usr/lib/python2.3/pydoc.py", line 1198, in docother + chop = maxlen - len(line) +TypeError: unsupported operand type(s) for -: 'classobj' and 'int' +</pre> +<p>I have not yet clear what the cause is, but it is certainly quite +tricky.</p> +<p>There is also another subtle pitfall which is not directly related +to <tt class="literal"><span class="pre">super</span></tt> but which is often encountered working with <tt class="literal"><span class="pre">super</span></tt>. +This came up at least three or four times in the newsgroup, and there +are various independent bug reports on sourceforge about it, so possibly +you may face it too. Bjorn Pettersen was the first one who pointed out the +problem to me (see also bug report SF 729913): the issue is that</p> +<p><tt class="literal"><span class="pre">super(MyCls,</span> <span class="pre">self).__getitem__(5)</span></tt></p> +<p>works, but not</p> +<p><tt class="literal"><span class="pre">super(MyCls,</span> <span class="pre">self)[5]</span></tt>.</p> +<p>The problem is general to all special methods, not only to <tt class="literal"><span class="pre">__getitem__</span></tt>, +and the explanation for that has to do with the implementation of +attribute lookup for special methods. Clear explanations of what is +going on are provided by Michael Hudson as a comment to the bug report: +SF789262 and by Raymond Hetting as a comment to the bug report SF805304. +Shortly put, this is not a problem of <tt class="literal"><span class="pre">super</span></tt> per se, the problem is +that (using <tt class="literal"><span class="pre">__getitem__</span></tt> as example)</p> +<blockquote> +<tt class="literal"><span class="pre">x[5]</span> <span class="pre">==</span> <span class="pre">type(x).__getitem__(x,5)</span></tt></blockquote> +<p><em>only if</em> <tt class="literal"><span class="pre">__getitem__</span></tt> is explicitely defined in <tt class="literal"><span class="pre">type(x)</span></tt>. If +<tt class="literal"><span class="pre">type(x)</span></tt> does not define <tt class="literal"><span class="pre">__getitem__</span></tt> directly, but only +indirectly via delegation (i.e. overriding <tt class="literal"><span class="pre">__getattribute__</span></tt>), +then the second form works but not the first one, i.e. the <tt class="literal"><span class="pre">[]</span></tt> syntax +is not automatically converted to the second form, the working one.</p> +<p>This restriction will likely stay in Python because it would involve +a really big change and a loss of performances, so it has to be +considered just a documentation bug, since nowhere in +the docs it is mentioned that special calling syntaxes (such as +the <tt class="literal"><span class="pre">[]</span></tt> call, the <tt class="literal"><span class="pre">iter</span></tt> call, the <tt class="literal"><span class="pre">repr</span></tt> call, etc. etc.) +are special and bypass <tt class="literal"><span class="pre">__getattribute__</span></tt>. Guido advice is: +just use the more explicit form and everything will work.</p> +<p>Finally, there may be other bugs and pitfalls I am not aware of. Certainly +there are many other issues and bugs in previous versions of Python that +I have not mentioned here, since they have been fixed, but that you may +encounter if you use Python 2.2 (and maybe even in 2.3).</p> +</div> +<div class="section" id="the-final-truth-when-it-comes-to-super-don-t-trust-even-guido-himself"> +<h1><a name="the-final-truth-when-it-comes-to-super-don-t-trust-even-guido-himself">The final truth: when it comes to <tt class="literal"><span class="pre">super</span></tt> don't trust even Guido himself!</a></h1> +<p>In order to explain how <tt class="literal"><span class="pre">super</span></tt> works, Guido describes a +"fully functional implementation of the super() built-in class in +pure Python" in "Unifying types and classes in Python 2.2". +Unfortunately, that implemenentation is more harmful than helpful, since +the current <tt class="literal"><span class="pre">super</span></tt> DOES NOT work in the same way :-( +Take for instance this example:</p> +<pre class="doctest-block"> +>>> class C(object): +... f='C.f' +</pre> +<pre class="doctest-block"> +>>> class D(C): +... f='D.f' +</pre> +<p>Here the <tt class="literal"><span class="pre">super</span></tt> works fine, +df</p> +<pre class="doctest-block"> +>>> print super(D,D()).f +C.f +</pre> +<p>but the class <tt class="literal"><span class="pre">Super</span></tt> described by Guido will raise an attribute +error when invoked as <tt class="literal"><span class="pre">Super(D,D()).f</span></tt>. Therefore Super is NOT +equivalent to the currently implemented <tt class="literal"><span class="pre">super</span></tt> built-in</p> +</div> +<div class="section" id="notes"> +<h1><a name="notes">Notes</a></h1> +<table class="footnote" frame="void" id="id6" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id2" name="id6">[2]</a></td><td>I wrote an essay on Python 2.3 Method Resolution Order which +you may find here:</td></tr> +</tbody> +</table> +<table class="footnote" frame="void" id="id7" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id3" name="id7">[3]</a></td><td>Raymond Hetting wrote a beautiful essay on descriptors here:</td></tr> +</tbody> +</table> +<table class="footnote" frame="void" id="id8" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id5" name="id8">[4]</a></td><td>David Mertz and me wrote a couple of articles on metaclasses; +the second one is the relevant one for the issues discussed here:</td></tr> +</tbody> +</table> +<table class="footnote" frame="void" id="id9" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a name="id9">[5]</a></td><td><a class="reference" href="http://groups.google.it/groups?hl=it&lr=&ie=UTF-8&threadm=2259b0e2.0304300625.4e0ebace%40posting.google.com&rnum=3&prev=/groups%3Fhl%3Dit%26lr%3D%26ie%3DUTF-8%26q%3Dsimionato%2Bpettersen%2Bsuper%26btnG%3DCerca%26meta%3Dgroup%253Dcomp.lang.python">http://groups.google.it/groups?hl=it&lr=&ie=UTF-8&threadm=2259b0e2.0304300625.4e0ebace%40posting.google.com&rnum=3&prev=/groups%3Fhl%3Dit%26lr%3D%26ie%3DUTF-8%26q%3Dsimionato%2Bpettersen%2Bsuper%26btnG%3DCerca%26meta%3Dgroup%253Dcomp.lang.python</a>.*</td></tr> +</tbody> +</table> +</div> +</div> +<hr class="footer" /> +<div class="footer"> +<a class="reference" href="super.txt">View document source</a>. +Generated on: 2004-06-13 20:23 UTC. +Generated by <a class="reference" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source. +</div> +</body> +</html> |