diff options
author | michele.simionato <devnull@localhost> | 2008-05-18 08:28:44 +0000 |
---|---|---|
committer | michele.simionato <devnull@localhost> | 2008-05-18 08:28:44 +0000 |
commit | f662d2dfc477f16e84b8adaf5888cf14b84c908c (patch) | |
tree | 7cab554405d264ad780ca46f99a922153555fcc1 /pypers | |
parent | e7db1ad5c6211663feb109257fcd668320e6bb00 (diff) | |
download | micheles-f662d2dfc477f16e84b8adaf5888cf14b84c908c.tar.gz |
Started working at the definitive documentation for super in Python 2.X
Diffstat (limited to 'pypers')
-rw-r--r-- | pypers/super/super2.txt | 779 |
1 files changed, 779 insertions, 0 deletions
diff --git a/pypers/super/super2.txt b/pypers/super/super2.txt new file mode 100644 index 0000000..4458a01 --- /dev/null +++ b/pypers/super/super2.txt @@ -0,0 +1,779 @@ +Ten things to know about ``super`` +==================================== + +:Author: Michele Simionato +:Email: michele.simionato@gmail.com +:Initial Draft: June 2004 +:Last Revision: May 2008 +:Version: 0.6 + +``super`` is Python a built-in, first introduced in Python 2.2 and +slightly improved and fixed in later versions, which is often +misunderstood by the average Python programmer. One of the reasons for +that, is the poor documentation of ``super``: at the time of this +writing (May 2008) the documentation is incomplete and in some parts +misleading and even wrong. For instance, the standard documentation +(even for the new 2.6 version +http://docs.python.org/dev/library/functions.html#super) still says:: + + 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. + +The first sentence is just plain wrong: ``super`` does not return the +superclass. There is no such a thing as "the" superclass in a Multiple +Inheritance (MI) world. 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 are +subtle pitfalls and dark corners of ``super`` which are not at all mentioned. +IMNSHO ``super`` is one of the most trickiest and surprising Python +constructs, and we absolutely needs a document to shed light on its secrets. +The present paper is a first step in this direction: it aims to tell you +the *truth* about ``super``. At least the amount of truth +I have discovered with my experimentations, which is certainly +not the whole truth ;) + +A fair warning is in order here: this document is aimed to expert +Pythonistas. It assumes you are familiar with new-style classes [#]_ +and the Method Resolution Order (MRO_) +concept; moreover a good understanding of descriptors_ would be extremely +useful in order to grasp this document. Some parts also require good +familiarity with metaclasses_. All in all, this paper is not for the faint +of heart ;) + +.. _MRO: http://www.python.org/download/releases/2.3/mro/ +.. _descriptors: http://users.rcn.com/python/download/Descriptor.htm +.. _metaclasses: http://www.ibm.com/developerworks/library/l-pymeta.html + +First thing: there is no superclass in a MI world +---------------------------------------------------------- + +Readers familiar will single inheritance languages, such as +Java or Smalltalk, will have a clear concept of superclass +in mind. This concept, however, has *no useful meaning* in Python or in +other multiple inheritance languages. I became convinced of this fact +after a discussion with Bjorn Pettersen and Alex Martelli +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: + + :: + + +-----+ + | T | + |a = 0| + +-----+ + / \ + / \ + +-------+ +-------+ + | A | | B | + | | | a = 2 | + +-------+ +-------+ + \ / + \ / + +-----+ + | C | + +-----+ + : + : instantiation + c + +>>> class T(object): +... a = 0 + +>>> class A(T): +... pass + +>>> class B(T): +... a = 2 + +>>> class C(A,B): +... pass + +>>> c = C() + +Which 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``. Iif ``super(C,c)`` 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 ``super(C,c).a`` should return 0. This +is NOT what happens. Instead, ``super(C,c).a`` walks trought the +method resolution order of the class of ``c`` (i.e. ``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 ``super(C,c).a`` +correctly returns the value 2, not 0: + +>>> super(C,c).a +2 + +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``). +The whole MRO is needed, not just the first superclass. + +So, using the word *superclass* in the standard doc is completely +misleading and should be avoided altogether. + +Second thing: ``super`` returns proxy objects +---------------------------------------------------- + +Having established that ``super`` cannot return and does not return the +mythical superclass, we may ask ourselves what the hell is returning +``super`` ;) The truth is that ``super`` returns proxy objects. + +Informally speaking, a proxy object is an object with +the ability to dispatch to methods of other classes via delegation. +Technically, ``super`` is a class overriding the ``__getattribute__`` +method. Instances of ``super`` are proxy objects providing +access to the methods in the MRO. The dispatch is done in such a way +that + +``super(cls, instance-or-subclass).meth(*args, **kw)`` + +corresponds to + +``right-method-in-the-MRO-applied-to(instance-or-subclass, *args, **kw)`` + +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 *both cases* a bound method is returned (one could naively +think that when a subclass is passed one gets an unbound method). + +For instance, in this example + +.. code-block:: python + + >>> class B(object): + ... def __repr__(self): + ... return "<instance of %s>" % self.__class__.__name__ + + >>> class C(B): + ... pass + + >>> class D(C): + ... pass + + >>> d = D() + +both + +.. code-block:: python + + >>> print super(C,d).__repr__ + <bound method D.__repr__ of <instance of D>> + +and + + +.. code-block:: python + + >>> print super(C,D).__repr__ + <bound method D.__repr__ of <class 'D'>> + +returns bound methods. This means that when you call the ``__repr__`` methods, +you will get + + +.. code-block:: python + + >>> print super(C,d).__repr__() + <instance of D> + +(here ``d``, a ``D`` instance, is being passed to ``__repr__``) and + +.. code-block:: python + + >>> print super(C, D).__repr__() + <instance of type> + +(here ``D``, an instance of the (meta)class ``type``, is being passed +to ``__repr__``). + +Reading the docs, one could think that in order to get unbound methods, +one would need to switch to the alternative syntax of ``super``, the single +argument syntax. This is actually untrue. To understand how unbound +methods can be retrieved we need to talk about descriptors. + +Third thing: ``super`` returns descriptor objects +---------------------------------------------------- + +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. 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 [#]_. You should read it before continuing this article, +since it explains all the details. However, for the sake of our discussion +of ``super``, it is enough to say that a *descriptor class* is just a +regular new-style class which implements a ``.__get__`` method with +signature ``__get__(self, obj, objtyp = None)``. A *descriptor object* +is just an instance of a descriptor class. + +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 ``C.descr`` is actually interpreted by Python as a +call to ``descr.__get__(None, C)``, whereas the same syntax for an +instance of C corresponds to a call to ``descr.__get__(c, type(c))``. + +The unbound method ``__repr__`` can be retrieved as + +.. code-block:: python + + >>> super(C,d).__repr__.__get__(None,D) # or with D instead of d + <unbound method D.__repr__> + +and we may check that it works correctly: + +.. code-block:: python + + >>> print _(d) + <instance of D> + +This is cumbersome and tricky, but it is the only way to get +the unbound method. Using the unbound form of ``super`` does +*not* return ``D.__repr__``: instead it returns ``super.__repr__`` +bound to the (unbound) super object ``super(C)``: + +.. code-block:: python + + >>> print super(C).__repr__() # same as repr(super(C)) + <super: <class 'C'>, NULL> + +Very tricky. Notice that ``super`` also redefines ``__new__``, +``__init``, ``__get__``, ``__getattribute``, as well as inheriting +other special attributes from ``object``. So using the single-argument +syntax you will dispatch to +these methods in ``super`` 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 + +.. code-block:: python + + >>> print super(C,C).__repr__() + <instance of type> + +does the right thing. + +This other example should shed further light. Suppose ``B`` +has a method called ``meth`` like this: + +.. code-block:: python + + >>> B.meth = lambda self :'You called B.meth with first argument %s' % self + +Then ``B.meth`` is an unbound method and, mislead by the documentation, +one could expect to be able to access it with the syntax ``super(C).meth``. +This is not the case. You get an error instead: + +.. code-block:: python + + >>> super(C).meth + Traceback (most recent call last): + ... + AttributeError: 'super' object has no attribute 'meth' + +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 ``super(C)`` in a super object +bound to ``d`` in this way: + +.. code-block:: python + + >>> boundsuper = super(C).__get__(d, D) # this is the same as super(C,d) + +Now I can access the bound method 'd.meth': + +.. code-block:: python + + >>> print boundsuper.meth + <bound method D.<lambda> of <instance of D>> + +As a consequence, ``__get__`` cannot be turned into a cooperative method +just by using ``super``: you would get the wrong ``get``. + +Fourth thing: the *unbound* syntax is a mess +------------------------------------------------------------------ + +Having established that the *unbound* syntax does not return unbound methods +one might ask what its purpose is. +The answer is that ``super(C)`` is intended to be used as an attribute in +other classes. Then the descriptor magic will automatically convert the +unbound syntax in the bound syntax. For instance: + +.. code-block:: python + + >>> class B(object): + ... a = 1 + >>> class C(B): + ... pass + >>> class D(C): + ... sup = super(C) + >>> d = D() + >>> d.sup.a + 1 + +This works since ``d.sup.a`` calls ``super(C).__get__(d,D).a`` which is +converted to ``super(C, d).a`` and retrieves ``B.a``. + +There is a single use case for the single argument +syntax of ``super`` 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`_. + +.. _new-style classes: http://www.python.org/download/releases/2.2.3/descrintro/#cooperation + +The idea there is to use the unbound super objects as private +attributes. For instance, in our example, we could define the +private attribute ``__sup`` in the class ``C`` as the unbound +super object ``super(C)``: + +.. code-block:: python + + >>> C._C__sup = super(C) + +With this definition inside the methods the syntax +``self.__sup.meth(arg)`` can be used +as an alternative to ``super(C, self).meth(arg)``, 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 ``__sup`` attributes can be hidden +in a metaclass and made automatic. So, all this seems to work: but +actually this *not* the case. + +Things may wrong in various case, for instance for classmethods, +as in this example: + +.. code-block:: python + + #<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> + +The last line raises an ``AttributeError: 'super' object has no attribute +'meth'.`` + +So, using a ``__super`` unbound super object is not a robust solution +(notice that everything would work by substituting ``self.__super.meth()`` +with ``super(C,self).meth()``. +In Python 3.0 all this has been resolved in a much better way. + +.. There are other ways to avoid repeating the class name, see for instance my cookbook recipe [#]_. + +If it was me, I would just remove the single argument syntax of ``super``, +making it illegal. But this would probably break someone code, so +I don't think it will ever happen in Python 2.X. Another solution would be just to +deprecate it. There is no need for this syntax, one can always circumvent +it. + +Fifth thing: ``super`` does not work with meta-attributes +---------------------------------------------------------------------- + +If you start using ``super`` intensively, soon or latter you will find +a number of subtilities. One of these is the fact that ``super`` does not +work well with the ``__name__`` special attribute. Consider this example: + +.. code-block:: python + + >>> class B(object): + ... "This is class B" + ... + >>> class C(B): + ... pass + ... + +Here the special (class) attribute ``__doc__`` is retrieved as you would expect: + +.. code-block:: python + + >>> super(C,C).__doc__ == super(C,C()).__doc__ == B.__doc__ + True + +On the other hand, the special attribute ``__name__`` is not +retrieved correctly: + +.. code-block:: python + + >>> 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__' + +The problem is that ``__name__`` is not just a plain class +attribute: it is actually a "getset descriptor" defined on +the metaclass "type" (try to run ``help(type.__dict__['__name__'])`` +and you will see for yourself). More in general, ``super`` 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 [#]_: here I am only interested +to the issues with ``super``. Consider this example: + +.. code-block:: python + + #<example1.py> + + class M(type): + "A metaclass with a class attribute 'a'." + a = 1 + + class B: + "An instance of M with a meta-attribute 'a'." + __metaclass__ = M + + class C(B): + "An instance of M with the same meta-attribute 'a'" + + if __name__ == "__main__": + print B.a, C.a # => 1 1 + print super(C,C).a #=> attribute error + + #</example1.py> + +If you run this, you will get an attribute error. This is a case +where ``super`` is doing the *right* thing, since 'a' is *not* 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 *not* 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 ``super`` is working correctly, but +still it may seems surprising at first. + +Sixth thing: special attribute access for special attributes is special ;) +---------------------------------------------------------------------------- + +There is also another subtle pitfall which is not directly related +to ``super`` but which is often encountered working with ``super``. +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 + +``super(MyCls, self).__getitem__(5)`` + +works, but not + +``super(MyCls, self)[5]``. + +The problem is general to all special methods, not only to ``__getitem__``, +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 Hettinger as a comment to the bug report SF805304. +Shortly put, this is not a problem of ``super`` per se, the problem is +that the special call ``x[5]`` (using ``__getitem__`` as example) is +converted to ``type(x).__getitem__(x,5)`` +*only if* ``__getitem__`` is explicitely defined in ``type(x)``. If +``type(x)`` does not define ``__getitem__`` directly, but only +indirectly via delegation (i.e. overriding ``__getattribute__``), +then the second form works but not the first one. + +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 ``[]`` call, the ``iter`` call, the ``repr`` call, etc. etc.) +are special and bypass ``__getattribute__``. Guido advice is: +just use the more explicit form and everything will work. + +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). + +Seventh thing: mixing super and non-super using methods is tricky +-------------------------------------------------------------------- + +Some years ago James Knight wrote an eassay titled +`Super considered harmful`_ [#]_ where he points out a few shortcomings +of ``super`` and makes an important recommendation: +*use super consistently, and document that you use it, as it is part of the +external interface for your class, like it or not*. +The issue is that a developer inheriting from a hierarchy written by somebody +else, has to know if the hierarchy author has used ``super`` internally +or not. For instance, consider this case, where the library author has +used ``super`` internally: + +.. code-block:: python + + class A(object): + def __init__(self): + print "A", + super(A, self).__init__() + + class B(object): + def __init__(self): + print "B", + super(B, self).__init__() + +If the application programmers knows that the library uses ``super`` internally, +he will use ``super`` and everything will work just fine; but it he does not +know if the library uses ``super`` he may be tempted to call ``A.__init__`` +and ``B.__init__`` directly, but this will end up in having ``B.__init__`` +called twice! + +.. code-block:: python + + class C(A,B): + def __init__(self): + print "C", + A.__init__(self) + B.__init__(self) + + # c = C() will print + +On the other hand, if the library does not uses ``super`` internally, + +.. code-block:: python + + class A(object): + def __init__(self): + print "A", + + class B(object): + def __init__(self): + print "B", + +the application programmer cannot use ``super`` either, otherwise +``B.__init__`` will not be called: + +.. code-block:: python + + class C(A,B): + def __init__(self): + print "C", + super(C, self).__init__() + + # c = C() will print + +So, if use a library featuring multiple inheritance, you must know if the +hierarchy was intended to be cooperative (using ``super``) or not. + +Eighth thing: argument passing in cooperative methods can fool you +---------------------------------------------------------------------- + +James Knight devolves a paragraph to the discussion of argument passing +in cooperative methods. Basically, if you want to be safe, all your cooperative +methods should have a compatible signature. There are various ways to +get a compatible signature, for instance you could accept everything (i.e. +your cooperative methods could have signature ``*args, **kw``) which is +a bit too much for me, or all of your methods could have exactly the same +arguments. The issue comes when you have default arguments, since your +MRO can change if you change your hierarchy, and argument passing may +break down. Here is one example + +.. code-block:: python + + class A(object): + def __init__(self): + print 'A' + + class B(object): + def __init__(self, a=None): + print 'B with a=%s' % a + super(B, self).__init__(a) + + class C(object): + def __init__(self, a): + print 'C with a=%s' % a + super(C, self).__init__() + + class D(B, C): + def __init__(self): + print 'D' + super(D, self).__init__() + + d = D() + +This works, but it is fragile (you see what will happen if you change +``D(B,C)`` with ``D(C,B)``?) and in general it is always difficult +to figure out which arguments will be passed to each method and in +which order (the order changing if you change the hierarchy) so it is +best just to use the same arguments everywhere (or not to use +cooperative methods altogether, if you have no need for cooperation). +There is no shortage of examples of trickiness in multiple inheritance +hierarchy; for instance I remember a post from comp.lang.python [#]_ +. Also, beware of situations in which you have +some old style classes mixing with new style classes: the result may +depend on the order of the base classes (see examples 2-2b and 2-3b +in `Super considered harmful`_. + +.. _Super considered harmful: http://fuhm.net/super-harmful/ + +Ninth thing: ``super`` had bugs in earlier versions of Python +----------------------------------------------------------------- + +There are various ``super`` pitfalls currently undocumented of which +the experienced Python programmer should be aware of. + +The unbound form of ``super`` does not play well with pydoc. +The problems is still there in Python 2.3.4 (see bug report SF729103) + +.. code-block:: python + + >>> class B(object): pass + ... + >>> class C(B): + ... 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 -: 'type' and 'int' + +I have not yet clear what the cause is, but it is certainly quite +tricky. An incompatibility between ``super`` was reported by Christian Tanzer +(SF902628); if you run the following, you will get a TypeError: + +.. code-block:: python + + #<ex.py> + + class C(object): + pass + + C.s = super(C) + + if __name__ == "__main__": + import doctest, __main__ + doctest.testmod(__main__) + + #<ex.py> + +BTW, I don't think this is related to ``super`` only since I have +found similar problems when playing with descriptors and doctest +some time ago (but I cannot reproduce the bug right now). + +Tenth and last thing: when it comes to ``super`` don't trust even Guido himself! +---------------------------------------------------------------------------------- + +In order to explain how ``super`` 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 implementation is more harmful than helpful, since +the current ``super`` DOES NOT work in the same way :-( +Take for instance this example: + +.. code-block:: python + + >>> class C(object): + ... f='C.f' + >>> class D(C): + ... f='D.f' + +Here the ``super`` works fine, + +.. code-block:: python + + >>> print super(D,D()).f + C.f + +but the class ``Super`` described by Guido will raise an attribute +error when invoked as ``Super(D,D()).f``. Therefore ``Super`` is NOT +equivalent to the currently implemented ``super`` built-in. + +Conclusion: is there life beyond super? +------------------------------------------------------- + +In this paper I have argued that ``super`` is tricky, +however the existence of dark corners is not a compelling argument against +a language construct: after all, they are rare and there is an easy solution to +their obscurity, i.e. documenting them. +Also, even from experience I have come to believe that cooperative +methods are a wart (it is too difficult to reason about them, they are +fragile, and overall I see them as an unneeded complication in 99.9% +of the cases) they have their uses in a multiple inheritance world, as +Guido argues successfully in his essay (the canonical example being a +diamond diagram with ``.save`` methods which must be called +cooperatively). +The problem therefore is not with ``super`` or with cooperative +methods, the problem is with multiple inheritance itself (*if the +implementation is hard to explain, it's a bad idea*). + +I personally liked super, cooperative methods and multiple inheritance +for a couple of years, then I started working with Zope and my mind +changed completely. The problem is multiple inheritance itself: after +all Zope 2 did not use super at all but is a mess anyway. Inheritance +makes your code heavily coupled and difficult to follow (*spaghetti +inheritance*). I have not found a real life problem yet that I could +not solve with single inheritance + composition/delegation in a better +and more maintainable way than using multiple inheritance. +Nowadays I use multiple inheritance for quick and dirty hacks, +but never for designing new hierarchies from scratch. +There are alternative to multiple inheritance: for instance Ruby uses +mixins (they are a restricted multiple inheritance without cooperative +methods and with a well defined superclass, but they do not solve +the issue of name conflicts and the issue with the ordering of +the mixin classes); recently some people proposed the concepts +of traits (restricted mixin where name conflicts must be solved explicitely +and the ordering of the mixins does not matter) which is interesting. +In CLOS multiple inheritance works better since (multi-)methods +are defined outside classes and ``call-next-method`` is well integrated +in the language; +it is simpler to track down the ancestors +of a single method than to wonder about the full class hierarchy. +The language SML (which nobody except academics use, but would deserve +better recognition) goes boldly in the direction of favoring composition over +inheritance and uses functors to this aim. This is an approach I like very +much on the paper, but I lack real experience in a large code base to judge +merits and demerits of this approach. + +Notes +----------------- + +.. [#] http://www.python.org/download/releases/2.2.3/descrintro/ +.. [#] I wrote an essay on Python 2.3 Method Resolution Order which + you may find here: http://www.python.org/download/releases/2.3/mro/ +.. [#] Raymond Hetting wrote a beautiful essay on descriptors: http://users.rcn.com/python/download/Descriptor.htm +.. [#] David Mertz and me wrote a trilogy of articles on metaclasses; + the second one is the relevant one for the issues discussed here: + http://www-128.ibm.com/developerworks/linux/library/l-pymeta2/ +.. [#] a thread proving that there is no useful concept of superclass + http://tinyurl.com/5ms8lk +.. [#] Python's Super is nifty, but you can't use it, http://fuhm.net/super-harmful +.. [#] A thread about subtle cooperative hierarchies http://tinyurl.com/3jqhx7 +.. [#] Traits: http://www.iam.unibe.ch/~scg/Research/Traits/ |