newb __init__ inheritance

H

hyperboogie

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
 
M

Maarten

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
 
P

Peter Otten

Maarten said:
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:
.... def __init__(self):
.... print "in a"
........ def __init__(self):
.... print "in b"
.... super(self.__class__, self).__init__() # wrong
....
Can you figure out what C() will print? Try it out if you can't.
The corrected code:
.... def __init__(self):
.... print "in b"
.... super(B, self).__init__()
....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.
 
E

Ethan Furman

hyperboogie said:
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~
 
C

Colin J. Williams

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.
 
C

Colin J. Williams

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.
 
H

hyperboogie

Hello everyone.
[snip]
main()
I'm not sure that the class initialization is required.
Good luck,

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
#
 
C

Chris Rebert

thank you everyone...
Still things are not working as expected... what am I doing wrong?
# 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
 
H

hyperboogie

On Sun, Mar 11, 2012 at 3:18 AM, hyperboogie wrote:



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


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?
 
H

hyperboogie

On Sun, Mar 11, 2012 at 3:18 AM, hyperboogie wrote:



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


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?
 
C

Chris Rebert

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
 
I

Ian Kelly

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
 
I

Ian Kelly

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
 
P

Peter Otten

Ian said:
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()?
 
H

hyperboogie

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...
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,563
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top