[AstroPy] Coding Guidelines draft (comments encouraged)
Erik Bray
embray at stsci.edu
Mon Jul 25 16:45:20 EDT 2011
On 07/25/2011 08:09 AM, Erik Tollerud wrote:
> I have made a new version of the coding guidelines and posted them to:
> http://astropy.org/development/codeguide.html
>
> This version incorporates most of the feedback we've gotten so far on
> this thread, so if you've suggested something, you might want to look
> to make sure what's in there is what you had in mind. In particular,
> Michael, you may want to look at the new phrasing for the data file
> limit. Additionally, a few of you may want to look over the new
> phrasing for when C extensions are acceptable.
>
>
> One thing I have *not* yet altered is the section on super() and
> multiple inheritance, as the discussion does not seem to have
> concluded.
Allow me to add a little more fuel to the discussion then :)
First, for some additional motivating background, here's a post by Guido
on the history of class method resolution orders (MROs) in Python, and
the rationale for the current solution:
http://python-history.blogspot.com/2010/06/method-resolution-order.html
It's easier reading than any PEP on the topic, so I would consider it
worth reading for anyone who would like more background.
The recommendation given in the current Coding Guidelines completely
breaks the intended MRO for __init__(). In this example A.__init__() is
called twice (as well as object.__init__(), though this does nothing)!
The effective MRO is D->B->A->object->C->A->object. You can see this
for yourself if you take the original example and add some print statements:
>>> class A(object):
... inits = 0
... def __init__(self):
... self.inits += 1
... if self.inits > 1:
... print 'Calling A.__init__() again!'
... else:
... print 'Calling A.__init__() for the first time.'
...
>>> class B(A):
... def __init__(self):
... print 'Calling B.__init__().'
... A.__init__(self)
...
>>> class C(A):
... def __init__(self):
... print 'Calling C.__init__().'
... A.__init__(self)
...
>>> class D(C, B):
... def __init__(self):
... print 'Calling D.__init__().'
... B.__init__(self)
... C.__init__(self)
>>> D()
Calling D.__init__().
Calling B.__init__().
Calling A.__init__() for the first time.
Calling C.__init__().
Calling A.__init__() again!
<__main__.D object at 0x2afb22dd7750>
While this may be harmless in some cases, it's most likely not what the
developer really wants. And it's completely different from what Python
would otherwise do which is D->C->B->A->object. This is a much more
sensible MRO (and based on a well thought out algorithm that handles
numerous corner cases that you might not think of immediately). This is
also very difficult to do without cooperative super() calls.
Having some classes *not* using super() will break any code that does
try to use them as part of a cooperative super() call. So the better
policy is to *require* the use of super(), especially in __init__()
which is the most common case--I can't emphasize this enough :).
The problems with this, I think, are overstated: In the simplest and
most common case of single-inheritance using super(Foo, self).__init__()
is equivalent to Foo.__init__(self). In the case of inheriting from two
classes with no overlapping functionality--orthogonal bases as James put
it--again it's a moot point.
super() *only* adds complexity and/or confusion in diamond-like or even
more complex class hierarchies. But in these cases super() will always
make sure that the "right" thing is done. What Python's algorithm
considers "right" may not always be exactly what the developer wants,
but in the case of multiple inheritance Python follows its Zen by having
One Right Way to do it. And for a complex and confusing subject like
multiple inheritance that's a good thing.
Admittedly, the semantics for using super() in Python 2.x are
cumbersome. Python 3 at least allows calling super() with no arguments,
which is the same as super(__class__, self)--the most common way of
calling it. But that's just Python 3 :)
Erik
More information about the AstroPy
mailing list