Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #21386 > unrolled thread

newb __init__ inheritance

Started byhyperboogie <hyperboogie@gmail.com>
First post2012-03-08 07:25 -0800
Last post2012-03-12 02:09 -0700
Articles 15 — 7 participants

Back to article view | Back to comp.lang.python


Contents

  newb __init__ inheritance hyperboogie <hyperboogie@gmail.com> - 2012-03-08 07:25 -0800
    Re: newb __init__ inheritance Maarten <maarten.sneep@knmi.nl> - 2012-03-08 08:30 -0800
      Re: newb __init__ inheritance Peter Otten <__peter__@web.de> - 2012-03-08 18:03 +0100
    Re: newb __init__ inheritance Ethan Furman <ethan@stoneleaf.us> - 2012-03-08 09:34 -0800
    Re: newb __init__ inheritance "Colin J. Williams" <cjw@ncf.ca> - 2012-03-10 12:58 -0500
      Re: newb __init__ inheritance "Colin J. Williams" <cjw@ncf.ca> - 2012-03-10 17:47 -0500
        Re: newb __init__ inheritance hyperboogie <hyperboogie@gmail.com> - 2012-03-11 03:18 -0700
          Re: newb __init__ inheritance Chris Rebert <clp2@rebertia.com> - 2012-03-11 03:38 -0700
            Re: newb __init__ inheritance hyperboogie <hyperboogie@gmail.com> - 2012-03-11 03:56 -0700
              Re: newb __init__ inheritance Chris Rebert <clp2@rebertia.com> - 2012-03-11 04:37 -0700
              Re: newb __init__ inheritance Ian Kelly <ian.g.kelly@gmail.com> - 2012-03-11 05:40 -0600
              Re: newb __init__ inheritance Ian Kelly <ian.g.kelly@gmail.com> - 2012-03-11 05:52 -0600
              Re: newb __init__ inheritance Peter Otten <__peter__@web.de> - 2012-03-11 13:12 +0100
            Re: newb __init__ inheritance hyperboogie <hyperboogie@gmail.com> - 2012-03-11 03:56 -0700
    Re: newb __init__ inheritance hyperboogie <hyperboogie@gmail.com> - 2012-03-12 02:09 -0700

#21386 — newb __init__ inheritance

Fromhyperboogie <hyperboogie@gmail.com>
Date2012-03-08 07:25 -0800
Subjectnewb __init__ inheritance
Message-ID<1c6db866-6fa3-4de5-96de-51d6720a1300@x17g2000yqj.googlegroups.com>
Hello everyone.

This is my first post in this group.
I started learning python a week ago from the "dive into python" e-
book and thus far all was clear.
However today while reading chapter 5 about objects and object
orientation I ran into something that confused me.
it says here:
http://www.diveintopython.net/object_oriented_framework/defining_classes.html#fileinfo.class.example

"__init__ methods are optional, but when you define one, you must
remember to explicitly call the ancestor's __init__ method (if it
defines one). This is more generally true: whenever a descendant wants
to extend the behavior of the ancestor, the descendant method must
explicitly call the ancestor method at the proper time, with the
proper arguments. "

However later on in the chapter:
http://www.diveintopython.net/object_oriented_framework/userdict.html

it says:
"Methods are defined solely by their name, and there can be only one
method per class with a given name. So if a descendant class has an
__init__ method, it always overrides the ancestor __init__ method,
even if the descendant defines it with a different argument list. And
the same rule applies to any other method. "

My question is if __init__ in the descendant class overrides __init__
in the parent class how can I call the parent's __init__ from the
descendant class - I just overrode it didn't I?

Am I missing something more fundamental here?
Thanks

[toc] | [next] | [standalone]


#21389

FromMaarten <maarten.sneep@knmi.nl>
Date2012-03-08 08:30 -0800
Message-ID<13988849.1044.1331224217273.JavaMail.geo-discussion-forums@ynnk21>
In reply to#21386
On Thursday, March 8, 2012 4:25:06 PM UTC+1, hyperboogie wrote:

> My question is if __init__ in the descendant class overrides __init__
> in the parent class how can I call the parent's __init__ from the
> descendant class - I just overrode it didn't I?
> 
> Am I missing something more fundamental here?

No, you're not. 

However, you can explicitly call the __init__() method of a particular class. Hard-coding the class gives you:

class A(object):
    def __init__(self):
        print("In A")

class B(A):
    def __init__(self):
        A.__init__(self)
        print("In B")

Alternatively you can figure out the parent class with a call to super:

class C(A):
    def __init__(self):
        super(self.__class__, self).__init__()
        print("In C")

a = A() (prints "In A")
b = B() (prints "In A", "In B" on two lines)
c = C() (prints "In A", "In C" on two lines)

Hope this helps.

Maarten

[toc] | [prev] | [next] | [standalone]


#21390

FromPeter Otten <__peter__@web.de>
Date2012-03-08 18:03 +0100
Message-ID<mailman.514.1331226222.3037.python-list@python.org>
In reply to#21389
Maarten wrote:

> Alternatively you can figure out the parent class with a call to super:

This is WRONG:

>         super(self.__class__, self).__init__()

You have to name the current class explicitly. Consider:

>> class A(object):
...     def __init__(self):
...             print "in a"
... 
>>> class B(A):
...     def __init__(self):
...             print "in b"
...             super(self.__class__, self).__init__() # wrong
... 
>>> class C(B): pass
... 
>>> 

Can you figure out what C() will print? Try it out if you can't.
The corrected code:

>>> class B(A):
...     def __init__(self):
...             print "in b"
...             super(B, self).__init__()
... 
>>> class C(B): pass
... 
>>> C()
in b
in a
<__main__.C object at 0x7fcfafd52b10>

In Python 3 you can call super() with no args; super().__init__() do the 
right thing there.

[toc] | [prev] | [next] | [standalone]


#21391

FromEthan Furman <ethan@stoneleaf.us>
Date2012-03-08 09:34 -0800
Message-ID<mailman.515.1331229151.3037.python-list@python.org>
In reply to#21386
hyperboogie wrote:
> Hello everyone.
> 
> This is my first post in this group.
> I started learning python a week ago from the "dive into python" e-
> book and thus far all was clear.
> However today while reading chapter 5 about objects and object
> orientation I ran into something that confused me.
> it says here:
> http://www.diveintopython.net/object_oriented_framework/defining_classes.html#fileinfo.class.example
> 
> "__init__ methods are optional, but when you define one, you must
> remember to explicitly call the ancestor's __init__ method (if it
> defines one). This is more generally true: whenever a descendant wants
> to extend the behavior of the ancestor, the descendant method must
> explicitly call the ancestor method at the proper time, with the
> proper arguments. "
> 
> However later on in the chapter:
> http://www.diveintopython.net/object_oriented_framework/userdict.html
> 
> it says:
> "Methods are defined solely by their name, and there can be only one
> method per class with a given name. So if a descendant class has an
> __init__ method, it always overrides the ancestor __init__ method,
> even if the descendant defines it with a different argument list. And
> the same rule applies to any other method. "
> 
> My question is if __init__ in the descendant class overrides __init__
> in the parent class how can I call the parent's __init__ from the
> descendant class - I just overrode it didn't I?
> 
> Am I missing something more fundamental here?
> Thanks

An excellent question.

What you subclass you are creating a new, different class.

class A(object):
     def __init__(self):
         print("this is class A's __init__")
     def method1(self, value):
         print(value)

class B(A):
     def __init__(self):
         print("this is class B's __init__")

test = B()
test.method1('42')

When it says that the subclass overrides methods of the same name, it 
means that if it finds the method in the subclass, it will stop looking 
and use the one it found.

So in the example above when Python creates test it will find __init__ 
in B and so won't bother looking in A for it.  However, when looking for 
'method1' Python does not find it in B, and so looks in A for it and, 
finding it there, uses that as B's method1.

If you want B's __init__ to also call A's __init__, you have to so 
explicity:

     def __init__(self):
         A.__init__(self)

or

     def __init__(self):
         super(B, self).__init__()

or with Python 3

     def __init__(self):
         super().__init__()

~Ethan~

[toc] | [prev] | [next] | [standalone]


#21461

From"Colin J. Williams" <cjw@ncf.ca>
Date2012-03-10 12:58 -0500
Message-ID<jjg4p3$lst$1@theodyn.ncf.ca>
In reply to#21386
On 08/03/2012 10:25 AM, hyperboogie wrote:
> Hello everyone.
>
> This is my first post in this group.
> I started learning python a week ago from the "dive into python" e-
> book and thus far all was clear.
> However today while reading chapter 5 about objects and object
> orientation I ran into something that confused me.
> it says here:
> http://www.diveintopython.net/object_oriented_framework/defining_classes.html#fileinfo.class.example
>
> "__init__ methods are optional, but when you define one, you must
> remember to explicitly call the ancestor's __init__ method (if it
> defines one). This is more generally true: whenever a descendant wants
> to extend the behavior of the ancestor, the descendant method must
> explicitly call the ancestor method at the proper time, with the
> proper arguments. "
>
> However later on in the chapter:
> http://www.diveintopython.net/object_oriented_framework/userdict.html
>
> it says:
> "Methods are defined solely by their name, and there can be only one
> method per class with a given name. So if a descendant class has an
> __init__ method, it always overrides the ancestor __init__ method,
> even if the descendant defines it with a different argument list. And
> the same rule applies to any other method. "
>
> My question is if __init__ in the descendant class overrides __init__
> in the parent class how can I call the parent's __init__ from the
> descendant class - I just overrode it didn't I?
>
> Am I missing something more fundamental here?
> Thanks

The mro function [Method Resolution Order]is not too well advertised in 
the docs.  This should illustrate its usage:

#!/usr/bin/env python

class A():
   def __init__(self):
     z= 1

   def ringA(self):
     print ('aaa')

   def ringB(self):
     print('bbb')

class B(A):
   def __init__(self):
     z= 2

   def ringB(self):
     print('BBB')

a= A()
b= B()
b.ringB()
b.ringA()
b.__class__.mro()[1].ringB(b)

z= 1
def main():
     pass

if __name__ == '__main__':
     main()
I'm not sure that the class initialization is required.

Good luck,

Colin W.

[toc] | [prev] | [next] | [standalone]


#21471

From"Colin J. Williams" <cjw@ncf.ca>
Date2012-03-10 17:47 -0500
Message-ID<jjglmi$dao$1@theodyn.ncf.ca>
In reply to#21461
On 10/03/2012 12:58 PM, Colin J. Williams wrote:
> On 08/03/2012 10:25 AM, hyperboogie wrote:
>> Hello everyone.
>>
[snip]
> main()
> I'm not sure that the class initialization is required.
>
> Good luck,
>
> Colin W.
When I wrote earlier, I wondered about the need for initialization.

With Version 2, both __new__ and __init__ were required, not in the 
example below, using version 3.2:
#!/usr/bin/env python

class A():

   def ringA(self):
     print ('aaa')

   def ringB(self):
     print('bbb')

class B(A):
   def __init__(self:)
   def ringB(self):
     print('BBB')

a= A()
b= B()
b.ringB()
b.ringA()
b.__class__.mro()[0].ringB(22)   #  22 is used for the ringB attribute
                                  #  Trial and error shows that any
                                  #  non-Null,including None for the
                                  #  argument gives the same result
z= 1
def main():
     pass

if __name__ == '__main__':
     main()

Colin W.

[toc] | [prev] | [next] | [standalone]


#21486

Fromhyperboogie <hyperboogie@gmail.com>
Date2012-03-11 03:18 -0700
Message-ID<2feb13ca-f83b-4843-995f-ee77e7505ecd@db5g2000vbb.googlegroups.com>
In reply to#21471
On Mar 11, 12:47 am, "Colin J. Williams" <c...@ncf.ca> wrote:
> On 10/03/2012 12:58 PM, Colin J. Williams wrote:> On 08/03/2012 10:25 AM, hyperboogie wrote:
> >> Hello everyone.
>
> [snip]
> > main()
> > I'm not sure that the class initialization is required.
>
> > Good luck,
>
> > Colin W.
>
> When I wrote earlier, I wondered about the need for initialization.
>
> With Version 2, both __new__ and __init__ were required, not in the
> example below, using version 3.2:
> #!/usr/bin/env python
>
> class A():
>
>    def ringA(self):
>      print ('aaa')
>
>    def ringB(self):
>      print('bbb')
>
> class B(A):
>    def __init__(self:)
>    def ringB(self):
>      print('BBB')
>
> a= A()
> b= B()
> b.ringB()
> b.ringA()
> b.__class__.mro()[0].ringB(22)   #  22 is used for the ringB attribute
>                                   #  Trial and error shows that any
>                                   #  non-Null,including None for the
>                                   #  argument gives the same result
> z= 1
> def main():
>      pass
>
> if __name__ == '__main__':
>      main()
>
> Colin W.

thank you everyone...
Still things are not working as expected... what am I doing wrong?
I'm working with python2 and have the following issues:

1. mro is not an attribute/function
2. inheritance is not working as expected:

# cat test.py
#!/usr/bin/python

class A():
   def __init__(self):
      z=1
      print "in A.__init__ z=", z

   def funcA(self):
      print "in funcA - class A"

   def funcB(self):
      print "in funcB - class A, z= ", z

class B(A):
   def __init__(self):
      A.__init__(self)
      print "in B.__init__ z=", z

   def funcB(self):
      print "in funcB - class B, z= ", z

a=A()
b=B()
b.funcB()
b.funcA()

# ./test.py
in A.__init__ z= 1    # This must be the __init__ from the
instantiation of a
in A.__init__ z= 1    # This must be the B.__init__ calling A.__init__
in B.__init__ z=      # Why isn't this working? z should have been
inherited from "A" right?
Traceback (most recent call last):
  File "./test.py", line 23, in <module>
    b=B()
  File "./test.py", line 17, in __init__
    print "in B.__init__ z=", z
NameError: global name 'z' is not defined
#

[toc] | [prev] | [next] | [standalone]


#21487

FromChris Rebert <clp2@rebertia.com>
Date2012-03-11 03:38 -0700
Message-ID<mailman.560.1331462311.3037.python-list@python.org>
In reply to#21486
On Sun, Mar 11, 2012 at 3:18 AM, hyperboogie <hyperboogie@gmail.com> wrote:
<snip>
> thank you everyone...
> Still things are not working as expected... what am I doing wrong?
<snip>
> # cat test.py
> #!/usr/bin/python
>
> class A():

You should be subclassing `object`, but that's a minor point which
isn't the cause of your problem.

>   def __init__(self):
>      z=1

This creates a *local variable* named "z". You want an *attribute*
named "z", so you should be doing:
    self.z = 1
instead. Same problem elsewhere; you must *always* explicitly use
`self` when referencing an attribute of the current object. Python !=
Java or C++.

Cheers,
Chris

[toc] | [prev] | [next] | [standalone]


#21488

Fromhyperboogie <hyperboogie@gmail.com>
Date2012-03-11 03:56 -0700
Message-ID<18769501.3541.1331463388634.JavaMail.geo-discussion-forums@ynkz21>
In reply to#21487
On Sunday, March 11, 2012 12:38:27 PM UTC+2, Chris Rebert wrote:
> On Sun, Mar 11, 2012 at 3:18 AM, hyperboogie wrote:
> <snip>
> > thank you everyone...
> > Still things are not working as expected... what am I doing wrong?
> <snip>
> > # cat test.py
> > #!/usr/bin/python
> >
> > class A():
> 
> You should be subclassing `object`, but that's a minor point which
> isn't the cause of your problem.
> 
> >   def __init__(self):
> >      z=1
> 
> This creates a *local variable* named "z". You want an *attribute*
> named "z", so you should be doing:
>     self.z = 1
> instead. Same problem elsewhere; you must *always* explicitly use
> `self` when referencing an attribute of the current object. Python !=
> Java or C++.
> 
> Cheers,
> Chris

Thanks ... works great now. 
Two last questions:

1. What do you mean by "subclassing `object`"?
2. Is the mro function available only on python3?

[toc] | [prev] | [next] | [standalone]


#21490

FromChris Rebert <clp2@rebertia.com>
Date2012-03-11 04:37 -0700
Message-ID<mailman.562.1331465879.3037.python-list@python.org>
In reply to#21488
On Sun, Mar 11, 2012 at 3:56 AM, hyperboogie <hyperboogie@gmail.com> wrote:
> On Sunday, March 11, 2012 12:38:27 PM UTC+2, Chris Rebert wrote:
>> On Sun, Mar 11, 2012 at 3:18 AM, hyperboogie wrote:
>> <snip>
>> > thank you everyone...
>> > Still things are not working as expected... what am I doing wrong?
>> <snip>
>> > # cat test.py
>> > #!/usr/bin/python
>> >
>> > class A():
>>
>> You should be subclassing `object`, but that's a minor point which
>> isn't the cause of your problem.
>>
>> >   def __init__(self):
>> >      z=1
>>
>> This creates a *local variable* named "z". You want an *attribute*
>> named "z", so you should be doing:
>>     self.z = 1
>> instead. Same problem elsewhere; you must *always* explicitly use
>> `self` when referencing an attribute of the current object. Python !=
>> Java or C++.
>>
>> Cheers,
>> Chris
>
> Thanks ... works great now.
> Two last questions:
>
> 1. What do you mean by "subclassing `object`"?

Your classes should (ultimately) subclass the built-in class named
"object". In your case:
    class A(object):
    # …rest same as before…

This ensures that your classes are new-style rather than old-style
(the latter is deprecated); see:
http://docs.python.org/glossary.html#term-new-style-class

> 2. Is the mro function available only on python3?

There's never been an mro function. Perhaps you mean the __mro__
attribute of classes (e.g. `B.__mro__`), which is available in Python
2.2+ and Python 3?

Cheers,
Chris

[toc] | [prev] | [next] | [standalone]


#21491

FromIan Kelly <ian.g.kelly@gmail.com>
Date2012-03-11 05:40 -0600
Message-ID<mailman.563.1331466085.3037.python-list@python.org>
In reply to#21488
On Sun, Mar 11, 2012 at 4:56 AM, hyperboogie <hyperboogie@gmail.com> wrote:
> 1. What do you mean by "subclassing `object`"?

In Python 2 there are two different types of classes: classic classes,
which are retained for backward compatibility, and new-style classes,
which were introduced in Python 2.2.  Classic classes are the default.
 In order to get a new-style class (strongly recommended), your class
must inherit directly or indirectly from object.  In the following, A
and B are classic classes, whereas C and D are new-style classes:

class A: pass

class B(A): pass

class C(object): pass

class D(C): pass

In Python 3, classic classes have been removed, and so all four of the
classes above would be new-style.

> 2. Is the mro function available only on python3?

No, but it is available only on new-style classes.  If you try it on a
classic class, you'll get an AttributeError.

Cheers,
Ian

[toc] | [prev] | [next] | [standalone]


#21492

FromIan Kelly <ian.g.kelly@gmail.com>
Date2012-03-11 05:52 -0600
Message-ID<mailman.564.1331466800.3037.python-list@python.org>
In reply to#21488
On Sun, Mar 11, 2012 at 5:40 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
>> 2. Is the mro function available only on python3?
>
> No, but it is available only on new-style classes.  If you try it on a
> classic class, you'll get an AttributeError.

And by the way, you probably shouldn't call the mro method directly.
That method is provided so that it can be overridden in order to
customize the MRO at class creation.  The proper (and faster) way to
look up the MRO for a class is using the __mro__ attribute, which
stores the result of the mro method when the class is initialized.

http://docs.python.org/library/stdtypes.html?highlight=mro#class.__mro__

Cheers,
Ian

[toc] | [prev] | [next] | [standalone]


#21493

FromPeter Otten <__peter__@web.de>
Date2012-03-11 13:12 +0100
Message-ID<mailman.565.1331467945.3037.python-list@python.org>
In reply to#21488
Ian Kelly wrote:

> On Sun, Mar 11, 2012 at 5:40 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
>>> 2. Is the mro function available only on python3?
>>
>> No, but it is available only on new-style classes.  If you try it on a
>> classic class, you'll get an AttributeError.
> 
> And by the way, you probably shouldn't call the mro method directly.
> That method is provided so that it can be overridden in order to
> customize the MRO at class creation.  The proper (and faster) way to
> look up the MRO for a class is using the __mro__ attribute, which
> stores the result of the mro method when the class is initialized.
> 
> http://docs.python.org/library/stdtypes.html?highlight=mro#class.__mro__

Is it a good idea to use mro() or __mro__ at all? Are there common use cases 
that cannot be addressed with super()?

[toc] | [prev] | [next] | [standalone]


#21489

Fromhyperboogie <hyperboogie@gmail.com>
Date2012-03-11 03:56 -0700
Message-ID<mailman.561.1331463391.3037.python-list@python.org>
In reply to#21487
On Sunday, March 11, 2012 12:38:27 PM UTC+2, Chris Rebert wrote:
> On Sun, Mar 11, 2012 at 3:18 AM, hyperboogie wrote:
> <snip>
> > thank you everyone...
> > Still things are not working as expected... what am I doing wrong?
> <snip>
> > # cat test.py
> > #!/usr/bin/python
> >
> > class A():
> 
> You should be subclassing `object`, but that's a minor point which
> isn't the cause of your problem.
> 
> >   def __init__(self):
> >      z=1
> 
> This creates a *local variable* named "z". You want an *attribute*
> named "z", so you should be doing:
>     self.z = 1
> instead. Same problem elsewhere; you must *always* explicitly use
> `self` when referencing an attribute of the current object. Python !=
> Java or C++.
> 
> Cheers,
> Chris

Thanks ... works great now. 
Two last questions:

1. What do you mean by "subclassing `object`"?
2. Is the mro function available only on python3?

[toc] | [prev] | [next] | [standalone]


#21524

Fromhyperboogie <hyperboogie@gmail.com>
Date2012-03-12 02:09 -0700
Message-ID<18399211.724.1331543376411.JavaMail.geo-discussion-forums@vbbfy7>
In reply to#21386
On Thursday, March 8, 2012 5:25:06 PM UTC+2, hyperboogie wrote:
> Hello everyone.
> 
> This is my first post in this group.
> I started learning python a week ago from the "dive into python" e-
> book and thus far all was clear.
> However today while reading chapter 5 about objects and object
> orientation I ran into something that confused me.
> it says here:
> http://www.diveintopython.net/object_oriented_framework/defining_classes.html#fileinfo.class.example
> 
> "__init__ methods are optional, but when you define one, you must
> remember to explicitly call the ancestor's __init__ method (if it
> defines one). This is more generally true: whenever a descendant wants
> to extend the behavior of the ancestor, the descendant method must
> explicitly call the ancestor method at the proper time, with the
> proper arguments. "
> 
> However later on in the chapter:
> http://www.diveintopython.net/object_oriented_framework/userdict.html
> 
> it says:
> "Methods are defined solely by their name, and there can be only one
> method per class with a given name. So if a descendant class has an
> __init__ method, it always overrides the ancestor __init__ method,
> even if the descendant defines it with a different argument list. And
> the same rule applies to any other method. "
> 
> My question is if __init__ in the descendant class overrides __init__
> in the parent class how can I call the parent's __init__ from the
> descendant class - I just overrode it didn't I?
> 
> Am I missing something more fundamental here?
> Thanks

Thank you so much everyone for you help. No doubt I still have a long way to go before I feel comfortable with python.
Appreciate all your help...

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web