Re: Multiple inheritance, super() and changing signature

2016-06-04 Thread Nagy László Zsolt

>
> Things to know about super:
> Part 1 http://www.artima.com/weblogs/viewpost.jsp?thread=236275
> Part 2 http://www.artima.com/weblogs/viewpost.jsp?thread=236278
> Part 3 http://www.artima.com/weblogs/viewpost.jsp?thread=237121
>
> The wonders of super:
> http://www.artima.com/weblogs/viewpost.jsp?thread=281127
>
> Mixins considered harmful:
> Part 1 http://www.artima.com/weblogs/viewpost.jsp?thread=246341
> Part 2 http://www.artima.com/weblogs/viewpost.jsp?thread=246483
> Part 3 http://www.artima.com/weblogs/viewpost.jsp?thread=254367
> Part 4 http://www.artima.com/weblogs/viewpost.jsp?thread=254507
>
> Traits as an alternative to MI and mixins:
> http://www.artima.com/weblogs/viewpost.jsp?thread=246488
>
> Generic functions as an alternative to mixins:
> http://www.artima.com/weblogs/viewpost.jsp?thread=237764
>
> The Method Resolution Order:
> https://www.python.org/download/releases/2.3/mro/
>
Very good links! This will be a good recreational reading for the next
two days.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-04 Thread Steven D'Aprano
On Sat, 4 Jun 2016 09:52 pm, Gregory Ewing wrote:

> Ian Kelly wrote:
>> 
>> It can't belong to a subclass; the MRI guarantees that. But it's not
>> necessarily a superclass either.
> 
> Er, yes, what I really meant to say was that it could
> be a class that got introduced into the MRO as a result
> of someone else subclassing your class.
> 
> So when you make a super call, you really have *no idea*
> what it's going to call.

That's the nature of inheritance in a MI world. If you try to specify a
particular superclass manually, you're in the position of the archetypal
drunk looking for his lost car keys under a street light "because the light
is better here". Sure, you always know which class you're calling, but
sometimes its the wrong class!

That's the mind-twisting part of MI. Just because your class inherits from
K, doesn't mean that you should be calling K's methods. Until you (generic
you) come to terms with that, you're going to struggle with MI regardless
of what you do.

It might help to read Michele Simionato's articles about super, multiple
inheritance and related topics. Michele has been working with issues
related to MI for many years and has a lot to say about them.

Things to know about super:
Part 1 http://www.artima.com/weblogs/viewpost.jsp?thread=236275
Part 2 http://www.artima.com/weblogs/viewpost.jsp?thread=236278
Part 3 http://www.artima.com/weblogs/viewpost.jsp?thread=237121

The wonders of super:
http://www.artima.com/weblogs/viewpost.jsp?thread=281127

Mixins considered harmful:
Part 1 http://www.artima.com/weblogs/viewpost.jsp?thread=246341
Part 2 http://www.artima.com/weblogs/viewpost.jsp?thread=246483
Part 3 http://www.artima.com/weblogs/viewpost.jsp?thread=254367
Part 4 http://www.artima.com/weblogs/viewpost.jsp?thread=254507

Traits as an alternative to MI and mixins:
http://www.artima.com/weblogs/viewpost.jsp?thread=246488

Generic functions as an alternative to mixins:
http://www.artima.com/weblogs/viewpost.jsp?thread=237764

The Method Resolution Order:
https://www.python.org/download/releases/2.3/mro/



Michele wrote:

"... the problem is multiple inheritance itself. 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."


and I think that is the most valuable lesson here. MI itself is, if not an
anti-pattern, at least a dangerous one.



-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-04 Thread Gregory Ewing

Steven D'Aprano wrote:

On Sat, 4 Jun 2016 11:06 am, Gregory Ewing wrote:

there is no need to use super. 


Except then you are precluding others from integrating your classes into
their class hierarchies.


And if you *do* use super, you're precluding integrating them
into other hierarchies that *don't* use super. You can't win.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-04 Thread Gregory Ewing

Ian Kelly wrote:


It can't belong to a subclass; the MRI guarantees that. But it's not
necessarily a superclass either.


Er, yes, what I really meant to say was that it could
be a class that got introduced into the MRO as a result
of someone else subclassing your class.

So when you make a super call, you really have *no idea*
what it's going to call.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Ian Kelly
On Jun 3, 2016 7:12 PM, "Gregory Ewing"  wrote:
>
> 4. It must not matter what order the methods in a super
> chain are called. This is because you cannot predict
> which method a given super call will invoke. It could
> belong to a subclass of the class making the call.

It can't belong to a subclass; the MRI guarantees that. But it's not
necessarily a superclass either.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Steven D'Aprano
On Sat, 4 Jun 2016 11:06 am, Gregory Ewing wrote:

> Nagy László Zsolt wrote:
>> I do not use diamond shapes in my hierarchy, I guess that does not
>> affect me. I may be wrong.
> 
> If there are no diamonds, 

In Python 3, or Python 2 with new-style classes, there are ALWAYS diamonds
when you use multiple inheritance.


> there is no need to use super. 

Except then you are precluding others from integrating your classes into
their class hierarchies.


> Explicit inherited method calls, done correctly, will
> work fine.
> 
> The only downside is that if your inheritance hierarchy
> changes, you need to review all your inherited calls
> to make sure they're still correct.
> 
> The use of super to address that issue seems attractive.
> However, super is only applicable if some rather stringent
> requirements are met:
> 
> 1. All the methods must have compatible signatures.
> 
> 2. Except for 3 below, all classes participating in the
> hierarchy must use super for a given method if any of
> them do, including any future subclasses.
> 
> 3. There must be a class at the top of the hierarchy
> that does *not* make super calls, to terminate the chain.

Normally that will be object.

Sometimes you need to prevent messages reaching object. But to my mind,
that's a code-smell, and indicates you're doing something wrong.

"Something wrong" may be multiple inheritance itself. There is a reason why
most languages don't allow MI at all, or only allow a much restricted
subset of it, in the form of mixins or traits.

And in fact, even using inheritance alone is harder than it seems.
Composition is just as powerful and usually easier to work with.

[...]

> If you can't satisfy *all* of these reqirements, then
> you can't use super. Sorry, but that's just the way
> super is.

If you can't use super, then chances are you can't use *anything*, including
manual calls to superclass methods. There's nothing magical about the use
of super itself. If you have problems with super, then you have two
choices:

(1) Manually walk the MRO making the same calls that super would have made,
in which case you'll have the same problems super did.

(2) DON'T walk the MRO making the same calls that super would have made, in
which case you will have all the problems that super solves. Namely, you
will either miss calling superclass methods, or you will call them two many
times.


In a straight linear single inheritance class hierarchy, walking the MRO is
trivial whether you use super or not, but not using super restricts you to
never using super. But in MI, not using super almost certainly means you're
doing it wrong.

(If you're lucky, you can get away with it if the methods you fail to call
aren't needed, or do nothing, and the methods you call twice are harmless.)




-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Gregory Ewing

Ben Finney wrote:

With classes all inheriting ultimately from ‘object’ (as all Python 3
classes do, and as all current Python 2 classes should), mutliple
inheritance inevitably places your classes in a diamond inheritance
pattern.


That's usually harmless, though, because object provides
very little functionality of its own.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Gregory Ewing

Nagy László Zsolt wrote:

I do not use diamond shapes in my hierarchy, I guess that does not
affect me. I may be wrong.


If there are no diamonds, there is no need to use super.
Explicit inherited method calls, done correctly, will
work fine.

The only downside is that if your inheritance hierarchy
changes, you need to review all your inherited calls
to make sure they're still correct.

The use of super to address that issue seems attractive.
However, super is only applicable if some rather stringent
requirements are met:

1. All the methods must have compatible signatures.

2. Except for 3 below, all classes participating in the
hierarchy must use super for a given method if any of
them do, including any future subclasses.

3. There must be a class at the top of the hierarchy
that does *not* make super calls, to terminate the chain.

4. It must not matter what order the methods in a super
chain are called. This is because you cannot predict
which method a given super call will invoke. It could
belong to a subclass of the class making the call.

If you can't satisfy *all* of these reqirements, then
you can't use super. Sorry, but that's just the way
super is.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Ben Finney
Ian Kelly  writes:

> Except that since we're discussing design for multiple inheritance,
> the positional argument "spam" is inappropriate. All arguments should
> be passed by keyword; the DolorSitAmet.__init__ method cannot be
> certain that LoremIpsum will be the next class in the MRO, and the
> actual next class might not expect spam to be the first positional
> argument.

You're right. That also allows us to stop handling unknown positional
arguments.

This does make it troublesome to design the function signature though,
and I can see why people balk at how to deal with the semantics of
‘super’ in Python 2::

class LoremIpsum(object):
def __init__(self, **kwargs):
spam = kwargs.pop('spam')
do_something_important_with(spam)
super(LoremIpsum, self).__init__(**kwargs)

class DolorSitAmet(LoremIpsum):
def __init__(self, **kwargs):
self.eggs = kwargs.pop('eggs')
self.beans = kwargs.pop('beans')
super(DolorSitAmet, self).__init__(**kwargs)

That's awful :-( because the initialiser's signature no longer shows any
sign of which parameters matter for this class.

It also sucks to need ‘dict.pop('name')’, instead of just ‘name’.


Keyword-only parameters make this easier and clearer::

class LoremIpsum:
def __init__(self, *, spam, **kwargs):
spam = kwargs.pop('spam')
do_something_important_with(spam)
super().__init__(**kwargs)

class DolorSitAmet(LoremIpsum):
def __init__(self, *, eggs=4, beans=None, **kwargs):
self.eggs = eggs
self.beans = beans
super().__init__(**kwargs)

I guess that's yet another reason to advocate Python 3 for all new code.

-- 
 \  “One time a cop pulled me over for running a stop sign. He |
  `\said, ‘Didn't you see the stop sign?’ I said, ‘Yeah, but I |
_o__)don't believe everything I read.’” —Steven Wright |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Ian Kelly
On Fri, Jun 3, 2016 at 2:16 PM, Ben Finney  wrote:
> If you're writing a custom initialiser that handles two additional
> parameters, then those parameters should not be present when you call
> the super() method's initialiser::
>
> # You specified Python 3, which allows simpler syntax.
>
> class LoremIpsum:
> def __init__(self, spam, *args, **kwargs):
> do_something_important_with(spam)
> super().__init__(*args, **kwargs)
>
> class DolorSitAmet(LoremIpsum):
> def __init__(self, spam, eggs=4, beans=None, *args, **kwargs):
> self.eggs = eggs
> self.beans = beans
> super().__init__(spam, *args, **kwargs)

Except that since we're discussing design for multiple inheritance,
the positional argument "spam" is inappropriate. All arguments should
be passed by keyword; the DolorSitAmet.__init__ method cannot be
certain that LoremIpsum will be the next class in the MRO, and the
actual next class might not expect spam to be the first positional
argument.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Ben Finney
Nagy László Zsolt  writes:

> Fortunately, I can change all of the classes, and extracting the
> common parameter into a common base class worked.

This is why Liskov's Substitution Principle is good: Thinking of it as a
law helps lead to better design.

In this case, the same parameter doing different things in different
sub-classes meant that instances of those sub-classes had difficulty
substituting for the superclass. Interrogating the design against the
LSP reveals that.

> Problem solved. Thank you for all your help!
> Cooperative classes are fantastic! :-)

I'm glad you discovered them :-)

-- 
 \   “Truth is stranger than fiction, but it is because fiction is |
  `\ obliged to stick to possibilities, truth isn't.” —Mark Twain, |
_o__)  _Following the Equator_ |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Ben Finney
Nagy László Zsolt  writes:

> So you are right: the custom __init__ in the BootstrapDesktop class is
> not really needed, and does not do anything useful in that particular
> class.

I disagree: setting initial attributes is a normal and useful case for
defining a custom initialiser.

> My original statement was this: "I have to initialize some default
> attributes", and for that I need to pass arguments.

Yes. If you need to initialise the instance, that's what a custom
‘__init__’ is for.

> The truthness of this statement is not affected by adding a useless
> override of a method (with the very same parameters). Even though I
> see that you are right in what you wrote, I think I don't understand
> the point because it seem unrelated.

My point was rather that if the custom initialiser does *nothing* except
call the superclass's initialiser, then there's no purpose to writing
the custom initialiser.


If you're writing a custom initialiser that handles two additional
parameters, then those parameters should not be present when you call
the super() method's initialiser::

# You specified Python 3, which allows simpler syntax.

class LoremIpsum:
def __init__(self, spam, *args, **kwargs):
do_something_important_with(spam)
super().__init__(*args, **kwargs)

class DolorSitAmet(LoremIpsum):
def __init__(self, spam, eggs=4, beans=None, *args, **kwargs):
self.eggs = eggs
self.beans = beans
super().__init__(spam, *args, **kwargs)

So the sub-class follows the Liskov Substitution Principle: every
DolorSitAmet instance should be substitutable for LoremIpsum instances,
and users that only expect a LoremIpsum instance should not need to know
any difference.

This entails that its methods (in this case the initialiser) will accept
the same parameters as ‘LoremIpsum.__init__’, and do the same things
with those parameters. We make that explicit by omitting the
*additional* parameters that we already handled, ‘eggs’ and ‘beans’,
from the next call in the chain.

-- 
 \“The difference between religions and cults is determined by |
  `\  how much real estate is owned.” —Frank Zappa |
_o__)  |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Michael Selik
On Fri, Jun 3, 2016 at 12:01 PM Nagy László Zsolt 
wrote:

> > Is the problem that the attribute or parameter has the same name in
> both base classes, but has different meanings in each?
> If they had different meanings, a simple rename would solve the problem.
>

Sometimes finding a good name ain't so simple.

> If you can't change the base classes, I've got some other solutions, but
> > they're more involved, so I'll wait to hear back.
> One possible solution being encapsulating an object instead of
> inheriting from it?
>

That's one option, creating a wrapper class that dispatches almost
everything to the contained class, except with one renamed attribute/method.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Nagy László Zsolt



Is the problem that the attribute or parameter has the same name in both
base classes, but has different meanings in each?
If they had different meanings, a simple rename would solve the problem. 
They have the same meaning.



If you can't change the base classes, I've got some other solutions, but
they're more involved, so I'll wait to hear back.
One possible solution being encapsulating an object instead of 
inheriting from it?


Fortunately, I can change all of the classes, and extracting the common 
parameter into a common base class worked.


Problem solved. Thank you for all your help!

Cooperative classes are fantastic! :-)
--
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Michael Selik
On Fri, Jun 3, 2016 at 10:41 AM Ian Kelly  wrote:

> On Fri, Jun 3, 2016 at 8:06 AM, Nagy László Zsolt 
> wrote:
> > There is still something I don't get: how to create cooperative classes
> > when some base classes share some of the parameters?
>
> Why do they need to share the same parameter?
>

Is the problem that the attribute or parameter has the same name in both
base classes, but has different meanings in each?

If so, and you're in control of every class in the inheritance hierarchy,
perhaps you can come up with more specific names so that the bases no
longer share the same attribute.

If you can't change the base classes, I've got some other solutions, but
they're more involved, so I'll wait to hear back.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Ian Kelly
On Fri, Jun 3, 2016 at 8:06 AM, Nagy László Zsolt  wrote:
>
>>> That's overly strict. As Raymond shows, it is easy to deal with
>>> changing method signatures in *cooperative* classes.
>> I must watch that for sure.
>
> All right, I have read this:
>
> https://rhettinger.wordpress.com/2011/05/26/super-considered-super/
>
> There is still something I don't get: how to create cooperative classes
> when some base classes share some of the parameters?

Why do they need to share the same parameter? Part of cooperative
design is that you can't really design each class in a vacuum; you
need to take the other classes they might get combined with into
account. Perhaps you can extract that parameter into another base
class that is shared by both:

class Root:
def __init__(self, *, param1, **kwds):
self.param1 = param1
super().__init__(**kwds)

class A(Root):
def __init__(self, *, param2, **kwds):
self.param2 = param2
super().__init__(**kwds)

class B(Root):
def __init__(self, *, param3, **kwds):
self.param3 = param3
super().__init__(**kwds)

class X(A, B):
pass

A and B can both depend on having param1 without stomping on each
other because they both inherit Root which requires it.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Nagy László Zsolt

>> That's overly strict. As Raymond shows, it is easy to deal with
>> changing method signatures in *cooperative* classes. 
> I must watch that for sure.

All right, I have read this:

https://rhettinger.wordpress.com/2011/05/26/super-considered-super/

There is still something I don't get: how to create cooperative classes
when some base classes share some of the parameters?

Here is an example modified from Raymond's post:

class A:
def __init__(self, param1, param2, **kwds):
self.param1 = param1
self.param2 = param2
super().__init__(**kwds)

class B:
def __init__(self, param1, param3, **kwds):
self.param1 = param1
self.param3 = param3
super().__init__(**kwds)


class X(A,B):
def __init__(self, param1, param2, param3, **kwds):
print("param1=",param1,"param2=",param2,"param3=",param3)
super().__init__(param1=param1,param2=param2,param3=param3,**kwds)

print(X.__mro__)
x = X(1,2,3)


Result:

(, , ,
)
param1= 1 param2= 2 param3= 3
Traceback (most recent call last):
  File "test.py", line 20, in 
x = X(1,2,3)
  File "test.py", line 17, in __init__
super().__init__(param1=param1,param2=param2,param3=param3,**kwds)
  File "test.py", line 5, in __init__
super().__init__(**kwds)
TypeError: __init__() missing 1 required positional argument: 'param1'

I could only find this as a solution:

class Root:
def __init__(self, **kwds):
pass

class A(Root):
def __init__(self, **kwds):
self.param1 = kwds['param1']
self.param2 = kwds['param2']
super().__init__(**kwds)

class B(Root):
def __init__(self, **kwds):
self.param1 = kwds['param1']
self.param3 = kwds['param3']
super().__init__(**kwds)


class X(A,B):
def __init__(self, param1, param2, param3, **kwds):
print("param1=",param1,"param2=",param2,"param3=",param3)
super().__init__(param1=param1,param2=param2,param3=param3,**kwds)

X(1,2,3)

But then self documentation and code completion becomes very problematic:

http://i.imgur.com/wzlh8uy.png


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Nagy László Zsolt


>> But I have to initialize some default attributes.
> Then the statement “there is NOTHING else here” must be false. Either
> the custom ‘__init__’ does something useful, or it doesn't.
Well... the custom __init__ method with nothing else just a super() call
was expressed there to show the super() call explicitly, and to
emphasize that in that particular class, super() is used instead of an
explicit base method call. It is not a pattern to be followed, just
syntactic sugar for the sake of the example.

So you are right: the custom __init__ in the  BootstrapDesktop class is
not really needed, and does not do anything useful in that particular
class.

My original statement was this: "I have to initialize some default
attributes", and for that I need to pass arguments. The truthness of
this statement is not affected by adding a useless override of a method
(with the very same parameters). Even though I see that you are right in
what you wrote, I think I don't understand the point because it seem
unrelated.

> All this is covered in Raymond Hettinger's material, so it's best that I
> just leave you to read that.
>
Is it available in written form? I have tried to watch the video, but
the sound quality is so poor that I cannot understand. I have tried to
search for a better one, but that is a different one. :-(


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Steven D'Aprano
On Fri, 3 Jun 2016 07:18 am, Random832 wrote:

> On Thu, Jun 2, 2016, at 13:36, Steven D'Aprano wrote:
[...]
>> But since the constructor/initialiser methods are so closely linked, many
>> people are satisfied to speak loosely and refer to "the constructor" as
>> either, unless they specifically wish to distinguish between __new__ and
>> __init__.
> 
> Where there is looseness, it comes from the fact that because __init__
> is always called even if __new__ returns a pre-existing object 

That's not quite correct. __init__ is not always called:

If __new__() does not return an instance of cls, then the new 
instance’s __init__() method will not be invoked.


https://docs.python.org/3/reference/datamodel.html#object.__new__


> people 
> often place code in __new__ which mutates the object to be returned,
> acting somewhat like a traditional constructor by assigning attributes
> etc.
> 
> But it is __init__ that acts like the thing that is called a constructor
> in many languages, and no-one's produced a single example of a language
> which uses "constructor" for something which allocates memory.

Yes you have: Python. Like it or not, it is common usage to call __new__ the
constructor and __init__ the initialiser. Even if the official docs are
agnostic on the issue, it is still widespread (but not universal) in the
Python community.

I have only come across two languages that split the "constructor" into two
methods, Objective C and Python. That does make Python rather special
compared to most other OO languages.

Objective C calls the part that allocates memory "alloc" (and is presumably
known as "the allocator") and the part which initialises it "init". "init"
is explicitly and officially known as the initialiser. Here's that link
again in case you missed it.

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/index.html#//apple_ref/occ/instm/NSObject/init

Even if you dismiss Python, you can't dispute that the official Apple docs
for Cocoa refer to initialiser rather than constructor.


Python also follows that pattern of splitting the "constructor" into two:
__new__ and __init__. Until Python 2.2 introduced new-style classes, it was
common to refer to __init__ as the constructor. For instance, I have the
Python Pocket Reference from Python 1.5 which describes __init__ as:

Constructor: initialize the new instance, self.

When object and new-style classes were introduced, people wanted to
distinguish them. Since __new__ constructs the object, and __init__
initialises it (even in old-style classes __init__ is said to *initialise*
the instance), it seems natural to call __new__ the constructor and
__init__ the initialiser.

Perhaps we ought to have called them the allocator and the initialiser. If
you want to lead the push for that terminology, please be my guest.



-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Nagy László Zsolt

> Raymond Hettinger gives an excellent presentation where he describes various
> problems with MI and gives solutions for them. I think this might be it:
>
> http://pyvideo.org/video/1094/the-art-of-subclassing-0
This is a much better version from one year later:

https://www.youtube.com/watch?v=miGolgp9xq8


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Ben Finney
Nagy László Zsolt  writes:

> > [...] 
> >> class BootstrapDesktop(BootstrapWidget, BaseDesktop):
> >> def __init__(self, appserver, session):
> >> # there is NOTHING else here, it just connects bootstrap widget
> >> implementation with desktop methods
> >> super(BootstrapDesktop, self).__init__(appserver, session)
> > The correct way to do that is to simply not define an __init__ method at
> > all.
> But I have to initialize some default attributes.

Then the statement “there is NOTHING else here” must be false. Either
the custom ‘__init__’ does something useful, or it doesn't.

> > See this explanation of C3 linearisation here:
> >
> > https://www.python.org/download/releases/2.3/mro/
> I do not use diamond shapes in my hierarchy, I guess that does not
> affect me. I may be wrong.

With classes all inheriting ultimately from ‘object’ (as all Python 3
classes do, and as all current Python 2 classes should), mutliple
inheritance inevitably places your classes in a diamond inheritance
pattern. And, what's more, you can't know when writing a class whether
it participates in a multiple inheritance hierarchy!

So in practice you must write every class so that it will behave well in
a diamond inheritance pattern.

All this is covered in Raymond Hettinger's material, so it's best that I
just leave you to read that.

-- 
 \“If the arguments in favor of atheism upset you, explain why |
  `\they’re wrong. If you can’t do that, that’s your problem.” |
_o__) —Amanda Marcotte, 2015-02-13 |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-03 Thread Nagy László Zsolt

>
> In Python 3, that will be automatic and you don't need to worry about it.
I'm using Python 3. I'm aware of old style and new style classes in
Python 2.
>
>
> [...] 
>> class BootstrapDesktop(BootstrapWidget, BaseDesktop):
>> def __init__(self, appserver, session):
>> # there is NOTHING else here, it just connects bootstrap widget
>> implementation with desktop methods
>> super(BootstrapDesktop, self).__init__(appserver, session)
> The correct way to do that is to simply not define an __init__ method at
> all.
But I have to initialize some default attributes. I could put them into
a method called something else, but that would have the same problem.
The question I put up is not specific to constructors, initializers or
whatever. It was a general question about super() being used in a
hierarchy with different signatures of the same method. I'm not sure why
everybody started to discuss __init__ and __new__ :-)

> Raymond Hettinger gives an excellent presentation where he describes various
> problems with MI and gives solutions for them. I think this might be it:
>
> http://pyvideo.org/video/1094/the-art-of-subclassing-0
I'm going to get back when I'm done with this video.  It will take some
hours. :-)

>> There is a single class (Widget) that has changed the signature of the
>> constructor. 
> Is this your code? Then simply fix Widget. MI in Python is cooperative: all
> the classes have to be designed for MI. It seems that Widget is not.
> (Possibly I have misdiagnosed the problem, and the fault lies elsewhere.)
If I knew what would be a good fix, I would do it. Somebody else
suggested to always use *args and **kwargs. That would be cooperative
for sure. But then It would be much harder to document the code (with
Sphinx for example), or use the syntax analyzer of an IDE (say PyCharm)
and have code completion. (Although the later is not a good argument
against the language itself.)
> Even if you got your wish, you couldn't use it until you're using Python 3.6
> or higher.
Yes, I know. I do this for fun, not for money.
> That's overly strict. As Raymond shows, it is easy to deal with
> changing method signatures in *cooperative* classes. 
I must watch that for sure.
> Perhaps you are unaware that manually calling the superclass method does not
> work correctly in cases of multiple inheritance? You end up either missing
> classes, and not calling their method, or calling them twice. That's why
> you need to use a proper linearisation algorithm, as used by super.
>
> See this explanation of C3 linearisation here:
>
> https://www.python.org/download/releases/2.3/mro/
I do not use diamond shapes in my hierarchy, I guess that does not
affect me. I may be wrong.

Thank you!

   Laszlo


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-02 Thread Marko Rauhamaa
Random832 :
> But from a class-definition perspective, __init__ is the one and only
> thing that should be called a constructor.

Not arguing agaist that, but from the *user's* perspective, I see the
class itself is the constructor function:

   class C: pass
   c = C()

You could say that the class statement in Python little else than
syntactic sugar for creating an object constructor.

For example, instead of:

   import math
   class Point:
   def __init__(self, x, y):
   self.x = x
   self.y = y
   def rotate(self, angle):
   self.x, self.y = (
   self.x * math.cos(angle) - self.y * math.sin(angle),
   self.x * math.sin(angle) + self.y * math.cos(angle))

you could write:

   import math, types
   def Point(x, y):
   def rotate(angle):
   nonlocal x, y
   x, y = (
   x * math.cos(angle) - y * math.sin(angle),
   x * math.sin(angle) + y * math.cos(angle))
   return types.SimpleNamespace(rotate=rotate)

> The fact that many languages don't have any way to override object
> allocation, and therefore no analogue to __new__, also contributes to
> this conclusion.

I see no point in Python having __new__, either. In fact, I can see the
point in C++ but not in Python.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-02 Thread Random832
On Thu, Jun 2, 2016, at 13:36, Steven D'Aprano wrote:
> On Thu, 2 Jun 2016 06:22 pm, Lawrence D’Oliveiro wrote:
> 
> > On Wednesday, June 1, 2016 at 8:02:14 AM UTC+12, Ben Finney wrote:
> >> (Note that ‘__init__’ is not a constructor, because it operates on the
> >> *already constructed* instance, and does not return anything.
> > 
> > Believe it or not, that *is* what “constructor” means in every OO
> > language. 
> 
> I don't believe it. 
> 
> C# is an OO language, and it distinguishes constructors and initialisers:
> 
> https://msdn.microsoft.com/en-us/library/bb397680.aspx

The methods described on that page as "constructors" operate *precisely*
as Lawrence said.

An "initializer" as that page discusses is not a method but is a kind of
expression, with no analogue in Python, which compiles to multiple
operations and 'returns' a value to be assigned to a variable. A
hypothetical Python analogue to the C# expression 'new c() { a = 1, b =
2 }', an "initializer", might compile to the following bytecode:
LOAD_GLOBAL (c); CALL_FUNCTION 0; DUP_TOP; LOAD_CONST (1); ROT_TWO;
STORE_ATTR (a); DUP_TOP; LOAD_CONST (2); ROT_TWO; STORE_ATTR (b); i.e.
yielding into the surrounding expression context an instance of type 'c'
which has been constructed and then subsequently had two of its
attributes (in C#'s case, fields and/or properties) set (or .Add methods
called, in the case of collection initializers)

> > Technically it should be called the “initializer”, but 
> > “constructor” is the accepted term for the special method that is called
> > to initialize a newly-allocated class instance.
> 
> Not in Python circles it isn't.

I suspect that the basis on which people refuse to accept it is a
(completely incorrect) sense that "constructor" has an inherent meaning
as allocating a new object, when no-one's been able to document that it
is used *anywhere*, Python or otherwise, in that sense. (I also
inherently dislike the notion that any given language community should
get to unilaterally decide, even if there were any such agreement, what
a term means, denying us a common way to talk about concepts shared
between languages to no benefit)

Your "python circles" seem to consist of people who are ignorant of how
other languages actually work and who want to believe that python is
special [i.e. in this case that python's __init__ is somehow different
in operation from C++ or C#'s or Java's constructors] when it is not. I
think it's more or less the same crowd, and the same motivation, as the
"python doesn't have variables" folks, and should be likewise ignored.

> But since the constructor/initialiser methods are so closely linked, many
> people are satisfied to speak loosely and refer to "the constructor" as
> either, unless they specifically wish to distinguish between __new__ and
> __init__.

Where there is looseness, it comes from the fact that because __init__
is always called even if __new__ returns a pre-existing object people
often place code in __new__ which mutates the object to be returned,
acting somewhat like a traditional constructor by assigning attributes
etc.

But it is __init__ that acts like the thing that is called a constructor
in many languages, and no-one's produced a single example of a language
which uses "constructor" for something which allocates memory.

Now, where "constructor" *does* often get misused, it is for the
new-expression in other languages, and for type.__call__ in Python,
people speak as if they're "calling the constructor" (rather than
calling something which ultimately calls both __new__ and __init__). But
from a class-definition perspective, __init__ is the one and only thing
that should be called a constructor.

The fact that many languages don't have any way to override object
allocation, and therefore no analogue to __new__, also contributes to
this conclusion. In these languages, new-expressions (or the like) are
the only way to call a constructor, so people associate object
allocation with constructors.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-02 Thread Ian Kelly
On Thu, Jun 2, 2016 at 11:36 AM, Steven D'Aprano  wrote:
> On Thu, 2 Jun 2016 06:22 pm, Lawrence D’Oliveiro wrote:
>
>> On Wednesday, June 1, 2016 at 8:02:14 AM UTC+12, Ben Finney wrote:
>>> (Note that ‘__init__’ is not a constructor, because it operates on the
>>> *already constructed* instance, and does not return anything.
>>
>> Believe it or not, that *is* what “constructor” means in every OO
>> language.
>
> I don't believe it.
>
> C# is an OO language, and it distinguishes constructors and initialisers:
>
> https://msdn.microsoft.com/en-us/library/bb397680.aspx
>
> (although they don't seem to mean quite the same as what they mean in
> Python).

Indeed. The "constructor" in that example is the equivalent of the
Python __init__ method. The "initializer" is not a part of the class
at all but just a syntactic sugar for creating an instance and setting
some of its properties at the same time in a single statement. It's
very similar to the C array initializer syntax, e.g.:

int myArray[] = {1, 2, 3, 4, 5};
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-02 Thread Steven D'Aprano
On Thu, 2 Jun 2016 06:22 pm, Lawrence D’Oliveiro wrote:

> On Wednesday, June 1, 2016 at 8:02:14 AM UTC+12, Ben Finney wrote:
>> (Note that ‘__init__’ is not a constructor, because it operates on the
>> *already constructed* instance, and does not return anything.
> 
> Believe it or not, that *is* what “constructor” means in every OO
> language. 

I don't believe it. 

C# is an OO language, and it distinguishes constructors and initialisers:

https://msdn.microsoft.com/en-us/library/bb397680.aspx

(although they don't seem to mean quite the same as what they mean in
Python).


Objective C is also an OO language, and it calls `init` the initializer:

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/index.html#//apple_ref/occ/instm/NSObject/init

The documentation doesn't specifically give a name to the `alloc` method,
but since it allocates memory for the instance, "allocator" is the obvious
term.

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/index.html#//apple_ref/occ/clm/NSObject/alloc

And `new` merely calls alloc, then init. (Although I'm lead to understand
that in older versions of Cocoa, `new` handled both allocation and
initialisation.)

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/index.html#//apple_ref/occ/clm/NSObject/new

Smalltalk, the grand-daddy of OOP languages, doesn't even have constructors
(at least not in the modern OOP sense):

http://www.slideshare.net/SmalltalkWorld/stoop-008fun-withsmalltalkmodel
http://image.slidesharecdn.com/stoop-008-funwithsmalltalkmodel-101025144609-phpapp02/95/8-oop-smalltalk-model-3-638.jpg?cb=1422578644

Any method can be used to create an object, there is no reserved name for
such a method.

Python is an OO language, what does it say?

The glossary doesn't define *either* constructor or initialiser (or
initializer):

https://docs.python.org/3/glossary.html

and the docs for __new__ and __init__ don't refer to them by either name:

https://docs.python.org/3/reference/datamodel.html#basic-customization

The docs do refer to the "object constructor expression", but that's the
call to the class, not the special method. And the term "initialiser"
or "initializer" is frequently used by Python developers to refer to
__init__:

https://rosettacode.org/wiki/Classes#Python


> Technically it should be called the “initializer”, but 
> “constructor” is the accepted term for the special method that is called
> to initialize a newly-allocated class instance.

Not in Python circles it isn't.

But since the constructor/initialiser methods are so closely linked, many
people are satisfied to speak loosely and refer to "the constructor" as
either, unless they specifically wish to distinguish between __new__ and
__init__.



-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-02 Thread Michael Selik
On Thu, Jun 2, 2016 at 4:26 AM Lawrence D’Oliveiro 
wrote:

> On Wednesday, June 1, 2016 at 8:02:14 AM UTC+12, Ben Finney wrote:
> > (Note that ‘__init__’ is not a constructor, because it operates on the
> > *already constructed* instance, and does not return anything.
>
> Believe it or not, that *is* what “constructor” means in every OO
> language. Technically it should be called the “initializer”, but
> “constructor” is the accepted term for the special method that is called to
> initialize a newly-allocated class instance.
>

Perhaps a Pythonista may have different jargon? Since we have two different
words (initializer, constructor), we may as well give them different
meanings so that they are maximally useful in conversation.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-06-02 Thread Lawrence D’Oliveiro
On Wednesday, June 1, 2016 at 8:02:14 AM UTC+12, Ben Finney wrote:
> (Note that ‘__init__’ is not a constructor, because it operates on the
> *already constructed* instance, and does not return anything.

Believe it or not, that *is* what “constructor” means in every OO language. 
Technically it should be called the “initializer”, but “constructor” is the 
accepted term for the special method that is called to initialize a 
newly-allocated class instance.

> Python's classes implement the constructor as ‘__new__’, and you very rarely
> need to bother with that.)

Python’s “__new__” goes beyond the capabilities of “constructors” in 
conventional OO languages.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Multiple inheritance, super() and changing signature

2016-05-31 Thread Steven D'Aprano
On Wed, 1 Jun 2016 02:10 am, Nagy Lc3a1szlc3b3 Zsolt wrote:

> Today I come across this problem for the N+1st time. Here are some
> classes for the example:


A couple of comments... if you're using Python 2, then you may be having
trouble because none of the classes shown below inherit from object. They
are all "old-style" classes. super needs at least one newstyle class to
work correctly.

In Python 3, that will be automatic and you don't need to worry about it.


[...] 
> class BootstrapDesktop(BootstrapWidget, BaseDesktop):
> def __init__(self, appserver, session):
> # there is NOTHING else here, it just connects bootstrap widget
> implementation with desktop methods
> super(BootstrapDesktop, self).__init__(appserver, session)

The correct way to do that is to simply not define an __init__ method at
all.


> Here is a part of the hierarchy:
> 
> Observable  AppServerSessionMixin
>  \  /
>   \/
>   Widget (__init__ with two parameters is first introduced here)
>  |
>VisualWidget
>  |  
>   BootstrapWidget BaseDesktop
>   \   /
>  BootstrapDesktop

For this to actually work, it needs to start:

  object
  /\
 /  \
Observable  AppServerSessionMixin
 \  /
  ... continues as above...


or something similar.



> The problem is obvious: 

Heh :-) There's nothing obvious about multiple inheritance problems.


> because of the method resolution order, the 
> super call in Observable.__init__ will try to call BaseDesktop.__init__
> without arguments, but that constructor has needs to arguments. The
> arguments are lost when Widget calls super() without them.

Raymond Hettinger gives an excellent presentation where he describes various
problems with MI and gives solutions for them. I think this might be it:

http://pyvideo.org/video/1094/the-art-of-subclassing-0

He also discusses super here:

https://rhettinger.wordpress.com/2011/05/26/super-considered-super/

You should also read the provocatively named "Super Considered Harmful"
here:

https://fuhm.net/super-harmful/

Despite the title, after a long discussion on the Python-Dev mailing list,
the author eventually admitted that in fact you do need to use super, and
that it works better than the alternatives. (Unfortunately, apart from a
partial change to the title, he didn't update the essay.) Nevertheless, MI
is always difficult, and he makes some good points in the essay.


[...]
> There is a single class (Widget) that has changed the signature of the
> constructor. 

Is this your code? Then simply fix Widget. MI in Python is cooperative: all
the classes have to be designed for MI. It seems that Widget is not.
(Possibly I have misdiagnosed the problem, and the fault lies elsewhere.)


> I was thinking about cutting the MRO list somehow into two 
> parts. It would be very nice to tell Python to create a separate MRO
> list for classes above and below the Widget class. Classes below Widget
> would not see any method above Widget, and that would allow me to use
> super() anywhere in the class hierarchy below Widget. I would only have
> to do an explicit call when the method signature is changed. That would
> save me a lot of parameter retyping and refactoring.

Even if you got your wish, you couldn't use it until you're using Python 3.6
or higher.


> In fact, I could never safely use super() in any case when the method
> signature has changed. When signatures are changed, method resolution
> must be done manually anyway.

No, that it incorrect. See Raymond Hettinger's talk and essay.


> Here is a proposal:
> 
> * method signature changes can be detected syntactically, relatively
> easily 

I don't think they can, at least not reliably.


> * raise an exception when super() is called in a method has changed 
> the signature (from any of base class(es))

That's overly strict. As Raymond shows, it is easy to deal with changing
method signatures in *cooperative* classes.


> * when a method changes signature, then split the MRO automatically into
> two parts. The tail of the MRO "below" the signature-changing-class
> should end in the method that has changed signature, and that method
> would be responsible for calling (or not calling) the method(s) with the
> same name inherited from base classes.

This sounds confusing and harder to get right than the current. Consider
that means that, in the worst case, you could split the MRO into two, then
two again, then two again, then two again... trying to debug this, or
understand it, would be a nightmare.

The MRO used by Python is a well-known linearisation studied in great
detail. It is proven to be effective and *correct*. Your proposal would
break that.

Perhaps you are unaware that manually calling the superclass method does not
work correctly in cases of multiple inheritance? You end up either missing
classes, and 

Re: Multiple inheritance, super() and changing signature

2016-05-31 Thread Ben Finney
Nagy László Zsolt  writes:

> Today I come across this problem for the N+1st time. Here are some
> classes for the example:

Thank you for the example.

(Note that ‘__init__’ is not a constructor, because it operates on the
*already constructed* instance, and does not return anything. Python's
classes implement the constructor as ‘__new__’, and you very rarely need
to bother with that.)


For the reasons you describe (among others), participating in multiple
inheritance is tricky.

As described in numerous articles, for example
,
the right way to do this is:

* Obey the Liskov Substitution Principle (sub-classes should override a
  method only when they allow all the parent's behaviour as well as
  their own).

  This also means that the sub-class should pass any unknown arguments
  along to the superclass's method to handle.

* Once a parameter is handled in a method, remove it from the set and
  pass only the remaining arguments along to the superclass's method.

> class Observable:
> """Implements the observer-observable pattern."""
>
> def __init__(self):
> # initialization code here...
> super(Observable, self).__init__()

This should be:

def __init__(self, **kwargs):
# …
super(Observable, self).__init__(**kwargs)

> class Widget(Observable, AppServerSessionMixin):
> def __init__(self, appserver, session):
> self.appserver = appserver
> self.session = session
> # general widget initialization code here...
> super(Widget, self).__init__()

This should be:

def __init__(self, appserver, session, **kwargs):
self.appserver = appserver
self.session = session
# …
super(Widget, self).__init__(**kwargs)

> class VisualWidget(Widget):
> def __init__(self, appserver, session):
> # some more code here for visually visible widgets...
> super(VisualWidget, self).__init__(appserver, session)

Since this function doesn't do anything with the parameters, it doesn't
need to have its own names for them:

def __init__(self, **kwargs):
# …
super(VisualWidget, self).__init__(**kwargs)

> class BaseDesktop:
> def __init__(self, appserver, session):
> # general code for all desktops is here...
> super(BaseDesktop, self).__init__(appserver, session)
>
> class BootstrapWidget(VisualWidget):
> def __init__(self, appserver, session):
> # bootstrap specific code for all widgets (not just desktops)
> super(BootstrapWidget, self).__init__(appserver, session)

And again:

def __init__(self, **kwargs):
# …
super(BaseDesktop, self).__init__(**kwargs)

def __init__(self, **kwargs):
# …
super(BootstrapWidget, self).__init__(**kwargs)

> class BootstrapDesktop(BootstrapWidget, BaseDesktop):
> def __init__(self, appserver, session):
> # there is NOTHING else here, it just connects bootstrap widget
> implementation with desktop methods
> super(BootstrapDesktop, self).__init__(appserver, session)

If the ‘__init__’ method literally does nothing except call the
superclass's method, don't define it in BootstrapDesktop at all.

And likewise for the rest: pass along all remaining arguments, and don't
write a do-nothing ‘__init__’.

> Of course, I could explicitly call constructors of base classes. But
> then I cannot use super() anywhere. Even not in places that are far
> down in the class hierarchy. This results in typing all method
> parameters many times, and also unnecesary refactoring.

You avoid this by the ‘**kwargs’ idiom (no need to name arguments you
don't explicitly handle), and by not writing any ‘__init__’ if you want
the default behaviour (call the superclass's method).

> This is time consuming and error prone.

As pointed out in Raymond Hettinger's article
,
multiple inheritance is inherently tricky and there is an irreducible
complexity that has to appear somewhere in your code.

> In fact, I could never safely use super() in any case when the method
> signature has changed. When signatures are changed, method resolution
> must be done manually anyway.

Use ‘**kwargs’, and always pass along the remaining ‘**kwargs’
minus-any-parameters-you-already-handled, to protect your existing
classes from unnecessary signature changes.

-- 
 \ “Creativity can be a social contribution, but only in so far as |
  `\ society is free to use the results.” —Richard M. Stallman |
_o__)  |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Multiple inheritance, super() and changing signature

2016-05-31 Thread Nagy László Zsolt
Today I come across this problem for the N+1st time. Here are some
classes for the example:


class Observable:
"""Implements the observer-observable pattern."""

def __init__(self):
# initialization code here...
super(Observable, self).__init__()

class AppServerSessionMixin:
# There is no __init__ here, this is a mixin
pass

class Widget(Observable, AppServerSessionMixin):
def __init__(self, appserver, session):
self.appserver = appserver
self.session = session
# general widget initialization code here...
super(Widget, self).__init__()

class VisualWidget(Widget):
def __init__(self, appserver, session):
# some more code here for visually visible widgets...
super(VisualWidget, self).__init__(appserver, session)

class BaseDesktop:
def __init__(self, appserver, session):
# general code for all desktops is here...
super(BaseDesktop, self).__init__(appserver, session)

class BootstrapWidget(VisualWidget):
def __init__(self, appserver, session):
# bootstrap specific code for all widgets (not just desktops)
super(BootstrapWidget, self).__init__(appserver, session)

class BootstrapDesktop(BootstrapWidget, BaseDesktop):
def __init__(self, appserver, session):
# there is NOTHING else here, it just connects bootstrap widget
implementation with desktop methods
super(BootstrapDesktop, self).__init__(appserver, session)

class JqueryUiWidget(VisualWidget):
def __init__(self, appserver, session):
# jquery ui specific code for all widgets (not just
desktops)   
super(JqueryUiWidget, self).__init__(appserver, session)

class JqueryUiDesktop(Widget, BaseDesktopMixIn):
def __init__(self, appserver, session):
# there is NOTHING else here, it just connects jquery ui widget
implementation with desktop methods
super(JqueryUiDesktop, self).__init__(appserver, session)

Here is a part of the hierarchy:

Observable  AppServerSessionMixin
 \  / 
  \/
  Widget (__init__ with two parameters is first introduced here)
 |
   VisualWidget
 |  
  BootstrapWidget BaseDesktop
  \   / 
 BootstrapDesktop

The problem is obvious: because of the method resolution order, the
super call in Observable.__init__ will try to call BaseDesktop.__init__
without arguments, but that constructor has needs to arguments. The
arguments are lost when Widget calls super() without them.

Of course, I could explicitly call constructors of base classes. But
then I cannot use super() anywhere. Even not in places that are far down
in the class hierarchy. This results in typing all method parameters
many times, and also unnecesary refactoring. This is time consuming and
error prone.

There is a single class (Widget) that has changed the signature of the
constructor. I was thinking about cutting the MRO list somehow into two
parts. It would be very nice to tell Python to create a separate MRO
list for classes above and below the Widget class. Classes below Widget
would not see any method above Widget, and that would allow me to use
super() anywhere in the class hierarchy below Widget. I would only have
to do an explicit call when the method signature is changed. That would
save me a lot of parameter retyping and refactoring.

In fact, I could never safely use super() in any case when the method
signature has changed. When signatures are changed, method resolution
must be done manually anyway.

Here is a proposal:

* method signature changes can be detected syntactically, relatively easily
* raise an exception when super() is called in a method has changed the
signature (from any of base class(es))
* when a method changes signature, then split the MRO automatically into
two parts. The tail of the MRO "below" the signature-changing-class
should end in the method that has changed signature, and that method
would be responsible for calling (or not calling) the method(s) with the
same name inherited from base classes.

Of course, this would require Python to calculate an MRO that depends on
the name of the method, and not just the class hierarchy. And also the
signatures of the methods, but those can also be changed dynamically. So
this may be a bad idea after all.

Please let me know what you think.

   Laszlo



-- 
https://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-08-01 Thread Steven Bethard
Michele Simionato wrote:
 I have found out that the more I use OOP, the less I
 use inheritance
 
 Just curious if others had a similar experience.

Definitely.  Though I think that's partly because I came from a Java 
background where it's a little more ingrained.  Since Python relies 
heavily on duck-typing, a lot of cases where I would subclass in Java I 
don't in Python.  In Python, I pretty much only create an inheritance 
hierarchy when I discover that two independent classes are sharing the 
same code.

STeVe
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-31 Thread Mike Meyer
Michele Simionato [EMAIL PROTECTED] writes:
 Mike Meyer:
 I think you're replying to me, but you didn't include any indication
 so I can't be sure.

 Oops, sorry, yes, I was replying to you.

 These two are cases of what I was talking about when I referred to the
 Church-Turing thesis.

 Well, let me put it in this way. If a language can implement a
 missing feature easily, then you are not really missing a big thing.
 And the feature may not be provided by default for sake of semplicity
 and/or uniformity of style. For instance Python does not have
 repeat-until
 loops, case statement, ternary operator, etc. (obviously I am not
 advocating to remove multiple inheritance now, I am justing
 speculating, talking about an hypotetic new Python-like language).

 Also, I don't see how they make the situation
 you are scared of above any better.

 It would discourage some people from some abuses, in the same sense the
 absence of repeat-until, case statemente, ternary operator etc are
 working right now.

These two points are working at cross purposes. If you can implement a
missing feature easily, then it doesn't do much to discourage abuses
of that feature.

  3. think differently and use multimethods

 I don't see how that would help at all. You haven't done anything
 about solving the base problem - that getting the methods into my
 classes cleanly needs multiple inheritance. Further, I don't need
 methods that are distinguished based on their arguments - they all
 take a fixed set of arguments, and operate on them and the state of
 the instance. None seem to be candidates for being multimethods. The
 mixin methods tend to provide general functionality, and get used in
 radically different places by the different child classes.

 You did miss the one alternative I considered: making the methods of
 Mixin stand-alone functions, and passing them extra arguments instead
 of using attributes of the instance. They would all then look like
 mixin_func(self.foo, self.bar, var, value). I decided that this wasn't
 as readable as inherting the methods.

 Uhm? I do not follow you. Multimethods would dispatch according
 to the type and would act differently on the childrens, dependending
 on their state. Perhaps I would need more information to understand
 what
 you have in mind.

Ok, let's take a typical Mixin example. All the classes work with HTML
pages rendered as soup. Some of them only deal with one page, others
walk through multiple pages to find some specific bit of
information. Each of them stores the page it's currently working on in
the attribute page.

The get_value method of Mixin extracts a string from self.page. You
pass it a string, it invokes methods of self.page to locate a string
that stands in a fixed relation to the string you passed in to it, and
returns the found string.

I don't see how this could be made a multimethod. What it does doesn't
change depending on selfs type. This example could trivially have been
done as a standalone function, as it only uses one attribute. Others
use more, say filling out forms based on a dictionary attribute, or
some such.

 But at the end my point is I would not feel much more constrained
 in expressivity if I did not have multiple inheritance in Python,
 and actually I have found out that the more I use OOP, the less I
 use inheritance.

 Just curious if others had a similar experience.

No, and yes. I think that using less inheritance as you get more
practice with it is a common thing. At first, it seems very cool, and
you're tempted to use it for everything. Then you find the problems
that this creates, and back off from it some. On the other hand, as my
understanding of inheritance deepened, I found myself using multiple
inheritance more, not less. Mostly, it's for mixins. Sometimes, I
really do need objects that have multiple types.

   mike
-- 
Mike Meyer [EMAIL PROTECTED]  http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-30 Thread Michele Simionato
If I understand correcly you have a situation like this:

Base

 |

Parent1  Mixin
  |  |
  |  |
  Children1

Base

 |

Parent2  Mixin
  |  |
  |  |
  Children2


Base

 |

Parent3
  |
  |
  Children3

The Base class is pretty general, Parent1, Parent2 and Parent3 are more
specific, Children1 and Children2 requires the Mixin class, but
Children3 does
not require it.

Let me note that this looks like a sensible design and that I agree
that in simple
situations multiple inheritance could be the simplest solution.
Nevertheless 1)
I am scared of the case where you have hundreds of methods coming from
everywhere (ex. Zope) and 2) even in simple situations a solution
without
multiple inheritance is not that much worse.

Various solutions (using pseudocode):

1. use single inheritance and attach the mixin methods by hand:

   class Children2(Parent2): pass

   for methodname, method in methods_of(Mixin):
   setattr(Children2, methodname, method)

  if you think this is ugly, use a metaclass to attach the methods for
  you. This is probably still ugly, since it is akin to reimplementing
  multiple inheritance by hand. Still, it can be done, if you really
want.

2. use single inheritance and delegation. If mixin is a proxy to
   the methods in the mixin (for instance implemented as an attribute
   descriptor) you could do

   class Children2(Parent2):
 mixin = Proxy(Mixin)

   c2 = Children2()

   and then c2.mixin.method(args) would actually call Mixin.method(c2,
args).
   I like this solution since it is clear where methods come from and
it scales
   better to complex situations (still if you have only 2 or 3 methods
   multiple inheritance could be pretty fine).

3. think differently and use multimethods

  There are implementations of multimethods in Python (for instance in
PEAK).
  This example looks like a good candidate for a multiple dispatch
solution.
  You would use single inheritance and promote the mixin methods to
  multimethods. BTW, I think multimethods are pretty
  nifty and I would welcome them in standard Python.



  Michele Simionato

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-30 Thread Mike Meyer

Michele Simionato [EMAIL PROTECTED] writes:

I think you're replying to me, but you didn't include any indication
so I can't be sure.

 If I understand correcly you have a situation like this:

 Base

  |

 Parent1  Mixin
   |  |
   |  |
   Children1

 Base

  |

 Parent2  Mixin
   |  |
   |  |
   Children2


 Base

  |

 Parent3
   |
   |
   Children3

Mostly right. What missing from the diagram is that there are three
Base classes: Base1, Base2 and Base3. They have no methods in
common.

 The Base class is pretty general, Parent1, Parent2 and Parent3 are more
 specific, Children1 and Children2 requires the Mixin class, but
 Children3 does
 not require it.

At least one ParentX also uses Mixin.

 Let me note that this looks like a sensible design and that I agree
 that in simple
 situations multiple inheritance could be the simplest solution.

Thank you.

 Nevertheless 1) I am scared of the case where you have hundreds of
 methods coming from everywhere (ex. Zope) and

Any tool can be abused.

 Various solutions (using pseudocode):
 1. use single inheritance and attach the mixin methods by hand:
 2. use single inheritance and delegation. If mixin is a proxy to
the methods in the mixin (for instance implemented as an attribute
descriptor) you could do

These two are cases of what I was talking about when I referred to the
Church-Turing thesis. Also, I don't see how they make the situation
you are scared of above any better.

 3. think differently and use multimethods

   There are implementations of multimethods in Python (for instance in
 PEAK).
   This example looks like a good candidate for a multiple dispatch
 solution.
   You would use single inheritance and promote the mixin methods to
   multimethods.

I don't see how that would help at all. You haven't done anything
about solving the base problem - that getting the methods into my
classes cleanly needs multiple inheritance. Further, I don't need
methods that are distinguished based on their arguments - they all
take a fixed set of arguments, and operate on them and the state of
the instance. None seem to be candidates for being multimethods. The
mixin methods tend to provide general functionality, and get used in
radically different places by the different child classes.

You did miss the one alternative I considered: making the methods of
Mixin stand-alone functions, and passing them extra arguments instead
of using attributes of the instance. They would all then look like
mixin_func(self.foo, self.bar, var, value). I decided that this wasn't
as readable as inherting the methods.

 BTW, I think multimethods are pretty nifty and I would welcome them
 in standard Python.

I wouldn't bet on it happening. They seem to violate explicit is
better than implicit.

   mike
-- 
Mike Meyer [EMAIL PROTECTED]  http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-30 Thread Michele Simionato
Mike Meyer:

 I think you're replying to me, but you didn't include any indication
 so I can't be sure.

Oops, sorry, yes, I was replying to you.

 These two are cases of what I was talking about when I referred to the
 Church-Turing thesis.

Well, let me put it in this way. If a language can implement a
missing feature easily, then you are not really missing a big thing.
And the feature may not be provided by default for sake of semplicity
and/or uniformity of style. For instance Python does not have
repeat-until
loops, case statement, ternary operator, etc. (obviously I am not
advocating to remove multiple inheritance now, I am justing
speculating, talking about an hypotetic new Python-like language).

 Also, I don't see how they make the situation
 you are scared of above any better.

It would discourage some people from some abuses, in the same sense the
absence of repeat-until, case statemente, ternary operator etc are
working right now.

  3. think differently and use multimethods

 I don't see how that would help at all. You haven't done anything
 about solving the base problem - that getting the methods into my
 classes cleanly needs multiple inheritance. Further, I don't need
 methods that are distinguished based on their arguments - they all
 take a fixed set of arguments, and operate on them and the state of
 the instance. None seem to be candidates for being multimethods. The
 mixin methods tend to provide general functionality, and get used in
 radically different places by the different child classes.

 You did miss the one alternative I considered: making the methods of
 Mixin stand-alone functions, and passing them extra arguments instead
 of using attributes of the instance. They would all then look like
 mixin_func(self.foo, self.bar, var, value). I decided that this wasn't
 as readable as inherting the methods.


Uhm? I do not follow you. Multimethods would dispatch according
to the type and would act differently on the childrens, dependending
on their state. Perhaps I would need more information to understand
what
you have in mind.

But at the end my point is I would not feel much more constrained
in expressivity if I did not have multiple inheritance in Python,
and actually I have found out that the more I use OOP, the less I
use inheritance.

Just curious if others had a similar experience.

 Michele Simionato

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-29 Thread Michele Simionato
Sion Arrowsmith
 That way lies Java

well, no, a dynamic language such as Python with the possibility of
adding methods on the fly and metaclasses could live pretty well
without
multiple inheritance. There would be no real loss
of power and hopefully less monstruosities such
a Zope 2. But maybe this is just wishful thinking ...

 Michele Simionato

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-29 Thread Mike Meyer
Michele Simionato [EMAIL PROTECTED] writes:

 adding methods on the fly and metaclasses could live pretty well
 without
 multiple inheritance. There would be no real loss
 of power and hopefully less monstruosities such
 a Zope 2. But maybe this is just wishful thinking ...

Um, no real loss of power? Well, in the sense that all languages are
turing-equivalent, maybe.

My current project includes a small set of classes that all deal with
web pages. The classes exist in three layers: the first layer is very
abstract, and provides a general mechanism. The second layer adapts
the general mechanasm to a specific case. The last layer provides
application-specific functionality. The classes intercommunicate, but
are generally completely unrelated to each other except for the more
concrete classes inheriting from the layer above.

So far, so good - it's all simple single inheritance.

Now, I have a class Utility that collects utility methods that are
useful for dealing with web pages: extracting data, filling out forms,
etc. These are provided as a mixin. The classes that need this
functionality inherits from it as well as their parent. The classes
that don't need it don't. This makes use of multiple inheritance.

Without multiple inheritance, I would have had to make the Utility
class a parent of all the most abstract classes. Some of the those
classes don't need that functionality - but their children do, so they
have to inherit from it. Children's needs shouldn't influence the
implementation of the child - that's simply ugly. Also, it creates an
apparent relationship between all the most abstract classes that
doesn't really exist.

Do you have a proposed solution that doesn't have these problems?

 mike
-- 
Mike Meyer [EMAIL PROTECTED]  http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-28 Thread Michele Simionato
 http://fuhm.org/super-harmful/

That is a pretty good page; I must say that my position is more radical
(i.e. it is not super which
is harmful, it is multiple inheritance itself that it is harmful: was I
going to design a new language
I would implement it *without* multiple inheritance).

   Michele Simionato

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-28 Thread Reinhold Birkenfeld
Michele Simionato wrote:
 http://fuhm.org/super-harmful/
 
 That is a pretty good page; I must say that my position is more radical
 (i.e. it is not super which
 is harmful, it is multiple inheritance itself that it is harmful: was I
 going to design a new language
 I would implement it *without* multiple inheritance).

Multiple inheritance can be very useful if not used in an unresponsible way.

For example, think of mixins. Or compatibility layers. Lately I had to adapt
a wx 2.6 application to wx 2.4 I could either search and substitute $BIGNUM
self.Bind() calls (which isn't done via simple Emacs magic, cause the 
replacement
varies), or I could write a compatibility mixin and derive every GUI class from
it, too.

Reinhold
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-28 Thread Sion Arrowsmith
Reinhold Birkenfeld  [EMAIL PROTECTED] wrote:
Michele Simionato wrote:
  was I
 going to design a new language
 I would implement it *without* multiple inheritance).

That way lies Java. The number of times I've wished an interface
were actually a mixin *shudder*

Multiple inheritance can be very useful if not used in an unresponsible way.

Exactly. I think the correct approach is to regard multiple
inheritence as a very advanced OO topic, leave it out of tutorials as
much as possible, and when finally introduced reinforce the idea that
it should be used only with caution. Speaking as someone who has used
it to commit monstrosities in C++ which I have grown to regret.

-- 
\S -- [EMAIL PROTECTED] -- http://www.chaos.org.uk/~sion/
  ___  |  Frankly I have no feelings towards penguins one way or the other
  \X/  |-- Arthur C. Clarke
   her nu becomeþ se bera eadward ofdun hlæddre heafdes bæce bump bump bump
-- 
http://mail.python.org/mailman/listinfo/python-list

Re: multiple inheritance super()

2005-07-28 Thread rafi
Michele Simionato wrote:
http://fuhm.org/super-harmful/
 
 
 That is a pretty good page; I must say that my position is more radical
 (i.e. it is not super which
 is harmful, it is multiple inheritance itself that it is harmful: was I
 going to design a new language
 I would implement it *without* multiple inheritance).
 
Michele Simionato
 

I do not agree on that point: Nobody is forced to used multiple 
inheritance, and when it is the right solution to be used, then it would 
be a shame not to have it. I remember the pain it was to implement some 
CORBA stuff using Java (moreover compared to C++) because of the lack of 
multiple inheritance.

-- 
rafi

Imagination is more important than knowledge.
(Albert Einstein)
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-27 Thread rafi
Scott David Daniels wrote:

 I do understand the lookup for foo: foo is provided by both classes A 
 and B and I do not state which one I want to use, so it takes the 
 first one in the list of inherited classes (order of the declaration). 
 However
 I cannot find an explanation (I may have googled the wrong keywords) 
 for the order of the __init__ calls from C. I was expecting (following 
 the same order as the method lookup):
 
 
 This should make it clear:
 class A (object):
 def __init__ (self):
 print 'A',
 super (A, self) .__init__ ()
 print '/A'
 class B (object):
 def __init__ (self):
 print 'B',
 super (B, self) .__init__ ()
 print '/B'
 class C (A, B):
 def __init__ (self):
 print 'C',
 super (C, self) .__init__ ()
 print '/C'
 
 C()
 

Gosh, based on your code I added an attribute foo on both A and B, and I 
now understand... The super goes through all the super classes init to 
find the attributes that may have name conflict and keep the value of 
the attribute baesd upon the order of the class declaration in the 
definition of C (here the value of foo in A). Am I right? I am mostly 
using old style (without type unification) init but this motivate the 
shift for the new style. Is there somewhere a document about this?

Thanks a lot Scott

-- 
rafi

Imagination is more important than knowledge.
(Albert Einstein)
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-27 Thread Michele Simionato
I am mostly
using old style (without type unification) init but this motivate the
shift for the new style. Is there somewhere a document about this?

Yes, see http://www.python.org/2.3/mro.html by yours truly

   Michele Simionato

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-27 Thread rafi
Michele Simionato wrote:
I am mostly
using old style (without type unification) init but this motivate the
shift for the new style. Is there somewhere a document about this?
 
 Yes, see http://www.python.org/2.3/mro.html by yours truly
 
Michele Simionato

Thanks a lot

-- 
rafi

Imagination is more important than knowledge.
(Albert Einstein)
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-27 Thread Mike Meyer
Michele Simionato [EMAIL PROTECTED] writes:

I am mostly
using old style (without type unification) init but this motivate the
shift for the new style. Is there somewhere a document about this?
 Yes, see http://www.python.org/2.3/mro.html by yours truly

I'd also recommend reading URL: http://fuhm.org/super-harmful/
. It's got some good practical advice on using super in your code.

   mike
-- 
Mike Meyer [EMAIL PROTECTED]  http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
-- 
http://mail.python.org/mailman/listinfo/python-list


multiple inheritance super()

2005-07-26 Thread km
Hi all,

In the following code why am i not able to access class A's object attribute - 
'a' ? I wishto extent  class D with all the attributes of its base classes. how 
do i do that ?

thanks in advance for enlightment ... 

here's the snippet 

#!/usr/bin/python

class A(object):
def __init__(self):
self.a = 1

class B(object):
def __init__(self):
self.b = 2

class C(object):
def __init__(self):
   self.c = 3
   
class D(B, A, C):
def __init__(self):
self.d = 4
super(D, self).__init__()

if __name__ == '__main__':
x =  D()
print x.a # errs with - AttributeError

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-26 Thread Peter Hansen
km wrote:
 Hi all,
 
 In the following code why am i not able to access class A's object attribute 
 - 'a' ? I wishto extent  class D with all the attributes of its base classes. 
 how do i do that ?
 
 thanks in advance for enlightment ... 
 
 here's the snippet 
 
 #!/usr/bin/python
 
 class A(object):
 def __init__(self):
 self.a = 1
 
 class B(object):
 def __init__(self):
 self.b = 2
 
 class C(object):
 def __init__(self):
self.c = 3

 class D(B, A, C):
 def __init__(self):
 self.d = 4
 super(D, self).__init__()

Each class should do a similar super() call, with the appropriate name 
substitutions.

Calls to __init__ must be made explicitly in subclasses, including in 
the case of multiple inheritance.

Also note that often (usually) you would like the __init__ call to come 
*before* other location initializations, and it's the safest thing to do 
unless you have clear reasons to the contrary.

-Peter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-26 Thread km
Hi peter,

ya got it working :-) now i understand mro better.

thanks,
KM
-
On Tue, Jul 26, 2005 at 04:09:55PM -0400, Peter Hansen wrote:
 km wrote:
  Hi all,
  
  In the following code why am i not able to access class A's object 
  attribute - 'a' ? I wishto extent  class D with all the attributes of its 
  base classes. how do i do that ?
  
  thanks in advance for enlightment ... 
  
  here's the snippet 
  
  #!/usr/bin/python
  
  class A(object):
  def __init__(self):
  self.a = 1
  
  class B(object):
  def __init__(self):
  self.b = 2
  
  class C(object):
  def __init__(self):
 self.c = 3
 
  class D(B, A, C):
  def __init__(self):
  self.d = 4
  super(D, self).__init__()
 
 Each class should do a similar super() call, with the appropriate name 
 substitutions.
 
 Calls to __init__ must be made explicitly in subclasses, including in 
 the case of multiple inheritance.
 
 Also note that often (usually) you would like the __init__ call to come 
 *before* other location initializations, and it's the safest thing to do 
 unless you have clear reasons to the contrary.
 
 -Peter
 -- 
 http://mail.python.org/mailman/listinfo/python-list
 

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-26 Thread rafi
Peter Hansen wrote:
 km wrote:
 
 Hi all,

 In the following code why am i not able to access class A's object 
 attribute - 'a' ? I wishto extent  class D with all the attributes of 
 its base classes. how do i do that ?
[snip]
 Each class should do a similar super() call, with the appropriate name 
 substitutions.
[snip]
 -Peter

A related question is about the order of the __init__ calls. Considering 
the following sample:

#--8---
class A (object):
 def __init__ (self):
 super (A, self) .__init__ ()
 print 'i am an A'
 def foo (self):
 print 'A.foo'

class B (object):
 def __init__ (self):
 super (B, self) .__init__ ()
 print 'i am a B'
 def foo (self):
 print 'B.foo'

class C (A, B):
 def __init__ (self):
 super (C, self) .__init__ ()
 print 'i am a C'

c = C ()
c.foo ()
#--8---

aerts $ python2.4 inheritance.py
i am a B
i am an A
i am a C
A.foo

I do understand the lookup for foo: foo is provided by both classes A 
and B and I do not state which one I want to use, so it takes the first 
one in the list of inherited classes (order of the declaration). However
I cannot find an explanation (I may have googled the wrong keywords) for 
the order of the __init__ calls from C. I was expecting (following the 
same order as the method lookup):

i am an A
i am a B
i am a C
A.foo

Thanks

-- 
rafi

Imagination is more important than knowledge.
(Albert Einstein)
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-26 Thread Bengt Richter
On Wed, 27 Jul 2005 12:44:12 +0530, km [EMAIL PROTECTED] wrote:

Hi all,

In the following code why am i not able to access class A's object attribute - 
'a' ? I wishto extent  class D with all the attributes of its base classes. 
how do i do that ?

thanks in advance for enlightment ... 

here's the snippet 

#!/usr/bin/python

class A(object):
def __init__(self):
self.a = 1

class B(object):
def __init__(self):
self.b = 2

class C(object):
def __init__(self):
   self.c = 3
   
class D(B, A, C):
def __init__(self):
self.d = 4
super(D, self).__init__()

if __name__ == '__main__':
x =  D()
print x.a # errs with - AttributeError


super(D, self) is going to find __init__ in the first base in the mro where it's
defined. So x.b will be defined, but not x.a.

I don't know what you are defining, but you could call the __init__ methods
of all the base classes by something like (untested)

for base in D.mro()[1:]:
if '__init__' in vars(base): base.__init__(self)

replacing your super line above in class D, but I would be leery of
using __init__ methods that way unless I had a really good rationale.

Regards,
Bengt Richter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-26 Thread Jeremy Moles
Thought I'm not sure (and don't have time to test) I'd guess it's
because you haven't explicitly called the __init__ method chain.

i.e., B calls A, C calls B, etc.

This is probably where the actual data gets pulled into scope.

On Wed, 2005-07-27 at 12:44 +0530, km wrote:
 Hi all,
 
 In the following code why am i not able to access class A's object attribute 
 - 'a' ? I wishto extent  class D with all the attributes of its base classes. 
 how do i do that ?
 
 thanks in advance for enlightment ... 
 
 here's the snippet 
 
 #!/usr/bin/python
 
 class A(object):
 def __init__(self):
 self.a = 1
 
 class B(object):
 def __init__(self):
 self.b = 2
 
 class C(object):
 def __init__(self):
self.c = 3

 class D(B, A, C):
 def __init__(self):
 self.d = 4
 super(D, self).__init__()
 
 if __name__ == '__main__':
 x =  D()
 print x.a # errs with - AttributeError
 

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: multiple inheritance super()

2005-07-26 Thread Jeremy Moles
Ignore my last response; just read it fully and realized how dumb my
response was. :)

On Wed, 2005-07-27 at 12:44 +0530, km wrote:
 Hi all,
 
 In the following code why am i not able to access class A's object attribute 
 - 'a' ? I wishto extent  class D with all the attributes of its base classes. 
 how do i do that ?
 
 thanks in advance for enlightment ... 
 
 here's the snippet 
 
 #!/usr/bin/python
 
 class A(object):
 def __init__(self):
 self.a = 1
 
 class B(object):
 def __init__(self):
 self.b = 2
 
 class C(object):
 def __init__(self):
self.c = 3

 class D(B, A, C):
 def __init__(self):
 self.d = 4
 super(D, self).__init__()
 
 if __name__ == '__main__':
 x =  D()
 print x.a # errs with - AttributeError
 

-- 
http://mail.python.org/mailman/listinfo/python-list