super() doesn't get superclass

B

Ben Finney

Michele Simionato said:
It is already possible to use a syntax like this

class MyClass(Base):
mixin(Mixin1, Mixin2, ...)

using P.J. Eby's trick for implementing what he calls class
decorators (see also
http://www.phyast.pitt.edu/~micheles/python/classinitializer.html)

But I would not use it, let's use the language we have, not
to invent our own.

Okay. How do we use the language we have to achieve what mixin classes
achieve in Ruby? Can you give an code example that you *would*
recommend for someone looking to do what mixin classes do?
 
B

Ben Finney

Michele Simionato said:
An example of fine usage of mixin is Tkinter; an example of bad
usage if Zope 2.

Which parts of those two very large code sets do I need to look at to
see the examples you have in mind? I was hoping you could demonstrate
with short code examples.
 
S

Steven D'Aprano

Currently irrelevant to the point. Whether for good or bad reasons, I
looked for a way to "get the superclass of A".

A.__base__ and A.__bases__ are, I believe, the "right" way to do that.

Everything about 'super'
— its name, parameter semantics, and documentation — all firmly led me
to believe that was the correct function for that purpose.

Name, I can accept.

Parameter semantics? That's borderline. "Get the superclass of A" looks
like it should take ONE and ONLY one argument, namely A. super()
typically takes two arguments, and only in non-typical use does it take a
single argument.

And documentation? From help(super):


class super(object)
| super(type) -> unbound super object
| super(type, obj) -> bound super object; requires isinstance(obj, type)
| super(type, type2) -> bound super object; requires issubclass(type2,
type)
| Typical use to call a cooperative superclass method:
| class C(B):
| def meth(self, arg):
| super(C, self).meth(arg)


Hmmm... it says it returns a super object, not a type or a class and
certainly not "the superclass". It doesn't say what a super object
actually is, but it doesn't say it is a type, or it would say "returns a
type object". Nor does it say it returns the superclass -- it doesn't
even use the term, with or without the hyphen.

And with a typical example shown right there, so close to the top, the
documentation is pretty clear that super() doesn't do what you imagined
it does.

So while I accept that the name of super() is misleading, I don't accept
that the documentation is misleading. Incomplete, yes, hard to
understand, yes, but not misleading.

At least, it didn't mislead _me_, and I'm pretty gullible sometimes...
*wink*
 
M

Michele Simionato

Okay. How do we use the language we have to achieve what mixin classes
achieve in Ruby? Can you give an code example that you *would*
recommend for someone looking to do what mixin classes do?

Since the language we have does have multiple inheritance, let's
use it to implement mixins. My point was that even if Python had
been implemented without multiple inheritance, it would have
been simple to implement mixins, or by copying the methods,
or by dispatching with __getattr__. So, multiple inheritance
is giving us very little for the point of view of mixins; OTOH,
multiple inheritance is giving us a lot of headaches for
what concerns cooperative methods.

Michele Simionato
 
M

Michele Simionato

Which parts of those two very large code sets do I need to look at to
see the examples you have in mind? I was hoping you could demonstrate
with short code examples.

Unfortunately you see the issue only when you program in
the large. Take for instance the Plone BaseContent class; I believe
its MRO contains something like 35 classes (I don't remember
the exact number now) in a multiple inheritance hierarchy.
Instances have some something like 400+ methods and attributes.
Now try to understand from which of the parent classes the
attributes came. For Tkinter things are much easier, see
the effbot "Introduction to Tkinter" for a discussion of
the mixin classes it uses. Then try something like
inspect.getmro(Tkinter.Label) , there are only 7 classes
in the hierarchy. Notice that even with single inheritance
you can run in deep hierarchies (Java docet).The problem,
as Guido once said, is the "inheritance is overrated".

Michele Simionato
 
B

Ben Finney

Michele Simionato said:
Since the language we have does have multiple inheritance, let's
use it to implement mixins.
...
So, multiple inheritance is giving us very little for the point of
view of mixins; OTOH, multiple inheritance is giving us a lot of
headaches for what concerns cooperative methods.

I may be obtuse, but the above statements seem to be professing
contradictory viewpoints.

Do you think multiple inheritance should or should not be used in
Python to do what mixins do?
My point was that even if Python had been implemented without
multiple inheritance, it would have been simple to implement mixins,
or by copying the methods, or by dispatching with __getattr__.

Can you give a code example of how you think mixins should be
implemented in Python, assuming the absence of multiple inheritance?
 
M

Michele Simionato

I may be obtuse, but the above statements seem to be professing
contradictory viewpoints.

Do you think multiple inheritance should or should not be used in
Python to do what mixins do?

If you want to use mixins in Python, then you should use
multiple inheritance, since multiple inheritance is already
there, no point in reinventing it. OTOH, one may argue that
there are better approaches than mixins, but this is another
topic.
Can you give a code example of how you think mixins should be
implemented in Python, assuming the absence of multiple inheritance?

I have various example somewhere in my hard disk, but now it is time
for me to go to job, so you will have to wait ;) But I
am sure others here can provide examples.

Michele Simionato
 
T

thebjorn

Happily A (and B too) will become invisible in Python 3000.

Michele Simionato

This is great news! Since it is for Py3K it seems clear to me that
super should be a keyword as well (but historically I'm not the best
at channeling Guido ;-)

-- bjorn
 
T

thebjorn

I may be obtuse, but the above statements seem to be professing
contradictory viewpoints.

How so? A language doesn't need MI to have mixins (e.g. Ruby does
this). This doesn't seem to contradict that MI is, in general, a
horrible solution to most problems -- one example being the general
difficulty in groking cooperative (super) methods. A single-
inheritance language, otoh, is also a chore to work with (for a
specific subset of designs) -- unless there is _some_ way to do
mixins. But for the general case I agree with Micele that delegation
is the better solution (Explicit is better than implicit).
Do you think multiple inheritance should or should not be used in
Python to do what mixins do?

Michele already answered this, Python has MI so it would just be
confusing to implement mixins any other way.
Can you give a code example of how you think mixins should be
implemented in Python, assuming the absence of multiple inheritance?

Googling for "Ruby mixins tutorial" gave me the following link:
http://www.juixe.com/techknow/index.php/2006/06/15/mixins-in-ruby/

If I tell you that self.something is written @something in Ruby, and
inheritance is written class Base < Parent (as opposed to class
Base(Parent):) everything else should be understandable..?

How to implement include and extend in Python is left as an excercise
for the reader.

-- bjorn
 
H

Hrvoje Niksic

Ben Finney said:
Yes. Those are the specific parameters to the function call, so that
*is* what I expect.

The specific parameters are a type and an instance. Those same
parameters can and do allow for an implementation that accesses
supertypes of type(self). That is in fact more logical; otherwise one
could simply iterate over A.__bases__ and we wouldn't need an
elaborate 'super' construct.

Not iterating only over A's superclasses is the entire *point* of
super. The only deficiency of super I see in this thread is
incomplete documentation.
 
S

Steven D'Aprano

Can you give a code example of how you think mixins should be
implemented in Python, assuming the absence of multiple inheritance?



I'll take a shot at it... use automatic delegation to the mixin class.



class Parrot(object):
def fly(self):
return "The parrot can fly short distances."
def talk(self):
return "I'm pining for the fjords."

class Albatross(object):
def fly(self):
return "The albatross is known to fly enormous distances."


# Now I want a talking Albatross, without using multiple inheritance.

class TalkingAlbatross(Albatross):
def __init__(self, *args, **kwargs):
# avoid triggering __setargs__
self.__dict__['mixin'] = Parrot()
# avoid using super() so Ben doesn't get cranky
self.__class__.__base__.__init__(self, *args, **kwargs)
def __getattr__(self, name):
return getattr(self.mixin, name)
def __hasattr__(self, name):
return hasattr(self.mixin, name)
def __delattr__(self, name):
return delattr(self.mixin, name)
def __setattr__(self, name, value):
return setattr(self.mixin, name, value)




Am I close?
 
M

Marshall T. Vandegrift

Michele Simionato said:
I am not against mixins (even if I am certainly very much against the
*abuse* of mixins, such as in Zope 2). What I would advocate (but I
realize that it will never happen in Python) is single inheritance +
mixins a la Ruby.

Ruby might be a bad example here. Although the Ruby language syntax
only supports single inheritance, mixins are implemented as multiple
inheritance under the hood. That is, inheriting from a class and
including a class as a mixin modifies the sub-/mixing class in exactly
the same way.

-Marshall
 
M

Michele Simionato

Ruby might be a bad example here. Although the Ruby language syntax
only supports single inheritance, mixins are implemented as multiple
inheritance under the hood. That is, inheriting from a class and
including a class as a mixin modifies the sub-/mixing class in exactly
the same way.

-Marshall

The difference is that there is no cooperation, so you don't need to
bang your
head in order to understand the method resolution order.

Michele Simionato
 
O

OKB (not okblacke)

Steven said:
class super(object)
| super(type) -> unbound super object
| super(type, obj) -> bound super object; requires isinstance(obj,
| type) super(type, type2) -> bound super object; requires
| issubclass(type2, type) Typical use to call a cooperative
| superclass method: class C(B):
| def meth(self, arg): super(C, self).meth(arg)

. . . but from the documentation on the website:

super(type[, object-or-type])
Return the superclass of type.

I do think this should be changed, since it really isn't true. It
should probably say something like "return the next element after "type"
in the MRO of "element-or-type".

--
--OKB (not okblacke)
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,981
Messages
2,570,188
Members
46,733
Latest member
LonaMonzon

Latest Threads

Top