4

Why this simple code doesn't work for Python 2.7 ? Please, help. Most likely I misuse super method in 'New Style' for classes.

class Mechanism(object):
 def __init__(self):
 print('Init Mechanism')
 self.__mechanism = 'this is mechanism'
 def get_mechanism(self):
 return self.__mechanism
class Vehicle(object):
 def __init__(self):
 print('Init Vehicle')
 self.__vehicle = 'this is vehicle'
 def get_vehicle(self):
 return self.__vehicle
class Car(Mechanism, Vehicle):
 def __init__(self):
 super(Car, self).__init__()
c = Car()
print(c.get_mechanism())
print(c.get_vehicle())

The error:

Init Vehicle
Traceback (most recent call last):
 File "check_inheritance.py", line 22, in <module>
 print(c.get_mechanism())
 File "check_inheritance.py", line 7, in get_mechanism
 return self.__mechanism
AttributeError: 'Car' object has no attribute '_Mechanism__mechanism'

EDIT

  1. Fixed def __init(self): in Mechanism class onto def __init__(self):
  2. The correct answer is to use super method in all classes. Not only in Car class. See the answer of Martijn Pieters
  3. Try to avoid double underscore __ for private variables. It is not a Python way (style of code). See the discussion for more info here.
asked Dec 18, 2017 at 18:05
6
  • 1
    your mechanism init is spelled wrong, should have two underscores before and after Commented Dec 18, 2017 at 18:08
  • There's also a misuse of super here: as currently structured, the Vehicle.__init__ method won't get called. You need a common root class (a base class for both Vehicle and Mechanism), and all subclasses, including Vehicle and Mechanism should call super. Commented Dec 18, 2017 at 18:17
  • @MartijnPieters: I think there's a valid question about use of super here, beyond the misspelled __init__ method. Commented Dec 18, 2017 at 18:21
  • In this case, you simply have a typo, and you forgot to call the next __init__ method in the chain, so the initializer for Mechanism is not called for two separate reasons. You really should not be using leading-double-underscore attributes unless you are building a framework for 3rd-parties to extend on, see Inheritance of private and protected methods in Python Commented Dec 18, 2017 at 18:21
  • You must call super in all child classes for co-operative multi-inheritance to work properly. Then the private variables will work just fine. Commented Dec 18, 2017 at 18:25

1 Answer 1

4

You have 2 issues:

  • You misnamed the __init__ method of Mechanism; you are missing two underscores.

  • Your __init__ methods do not cooperate correctly in a multiple inheritance situation. Make sure you always call super(...).__init__(), in all your __init__ methods.

The following code works:

class Mechanism(object):
 def __init__(self):
 super(Mechanism, self).__init__()
 print('Init Mechanism')
 self.__mechanism = 'this is mechanism'
 def get_mechanism(self):
 return self.__mechanism
class Vehicle(object):
 def __init__(self):
 super(Vehicle, self).__init__()
 print('Init Vehicle')
 self.__vehicle = 'this is vehicle'
 def get_vehicle(self):
 return self.__vehicle
class Car(Mechanism, Vehicle):
 def __init__(self):
 super(Car, self).__init__()

Demo:

>>> c = Car()
Init Vehicle
Init Mechanism
>>> print(c.get_mechanism())
this is mechanism
>>> print(c.get_vehicle())
this is vehicle

You should probably also not use double-underscore names. See Inheritance of private and protected methods in Python for the details, but the short reason is that you do not have a use case here for class-private names, as you are not building a framework meant to be extended by third parties; that's the only real usecase for such names.

Stick to single-underscore names instead, so _mechanism and _vehicle.

answered Dec 18, 2017 at 18:28
Sign up to request clarification or add additional context in comments.

10 Comments

Ah! I see. I have to use super(...).__init__() in ALL classes. Thank you, Martijn! Your change is working.
To Martijn -- Maybe I'm stuck in C++ style, but my opinion is to make all variables private inside class. Am I not right?
@foobar: you are indeed stuck in C++ style. Python doesn't have a privacy model; all attributes are available to all code running in the interpreter. Class 'private' attributes only given an automatic namespace, nothing more. That automatic namespace (the classname with a single leading underscore added) is there to prevent clashes with attributes in subclasses, not to make the names inaccessible from the outside.
@foobar: The Python style is to not use accessors, and to make attributes be the first-class public API instead. So instead of c.get_mechanism(), just use c.mechanism (a public attribute).
@foobar: I don't know why C++ prefers getters and setters, but I do know that in Java it is really hard to transition an API from public attributes to getters and setters later on. So to avoid that transition pain, the guideline is to always use getters and setters, regardless. In Python, converting an attribute to a property object (the Pythonic getter-setter pattern) is trivial, so you never have to worry about that future choice.
|

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.