Reputation: 2679
I'm sorry for the rather vague formulation of the question. I'll try to clarify what I mean through a simple example below. I have a class I want to use as a base for other classes:
class parent:
def __init__(self, constant):
self.constant = constant
def addconstant(self, number):
return self.constant + number
The self.constant
parameter is paramount for the usability of the class, as the addconstant
method depends on it. Therefore the __init__
method takes care of forcing the user to define the value of this parameter. So far so good.
Now, I define a child class like this:
class child(parent):
def __init__(self):
pass
Nothing stops me from creating an instance of this class, but when I try to use the addconstant
, it will obviously crash.
b = child()
b.addconstant(5)
AttributeError: 'child' object has no attribute 'constant'
Why does Python allow to do this!? I feel that Python is "too flexible" and somehow breaks the point of OOP and encapsulation. If I want to extend a class to take advantage of inheritance, I must be careful and know certain details of the implementation of the class. In this case, I have to know that forcing the user to set the constant
parameter constant is fundamental not to break the usability of the class. Doesn't this somehow break the encapsulation principle?
Upvotes: 0
Views: 55
Reputation: 184345
Because Python is a dynamic language. It doesn't know what attributes are on a parent
instance until parent
's initializer puts them there. In other words, the attributes of parent
are determined when you instantiate parent
and not an instant before.
In a language like Java, the attributes of parent
would be established at compile time. But Python class definitions are executed, not compiled.
In practice, this isn't really a problem. Yes, if you forget to call the parent class's initializer, you will have trouble. But calling the parent class's initializer is something you pretty much always do, in any language, because you want the parent class's behavior. So, don't forget to do that.
A sometimes-useful technique is to define a reasonable default on the class itself.
class parent:
constant = 0
def __init__(self, constant):
self.constant = constant
def addconstant(self, number):
return self.constant + number
Python falls back to accessing the class's attribute if you haven't defined it on an instance. So, this would provide a fallback value in case you forget to do that.
Upvotes: 1