Let's say I have a class TT
inheriting from a class T
and extending the behaviour of one of its methods, like so:
class T:
def __init__(self, p, b):
self.p = p
self.b = b
self.fun()
def fun(self):
a = self.p self.b
print(a)
class TT(T):
def __init__(self, p, b):
super().__init__(p, b)
def fun(self):
super().fun()
c = self.p*self.b
print(c)
What I'd like to have is TT.fun
relying on variables defined in T.fun
, a
in this example. The two obvious things that came to mind are to make T.fun
return a
, or to make a
an instance variable, but I don't find either satisfactory. Is there a way for TT.fun
to share the scope of the method it extends?
CodePudding user response:
The short answer is 'no', in particular because the fact a sub-class has a function named the same as one in the parent class does not mean those functions share anything. When you call super().fun()
, you're calling fun()
on the parent class, but this is the same as calling fun()
on a completely unrelated class - except insofar as the parent class is sharing it's state (instance variables).
Therefore, the only way for the sub-class instance to access computation occurring in the parent class instance's function is via normal patterns:
- Saving the result to the instance's state (instance variables).
- Returning the value, such that
super().fun()
becomesa = super().fun()
- Saving to to some other more-global-scope value (not recommended).
When you say 'neither way is satisfactory', you should probably dig a little deeper and examine why that is. There are alternatives, such as private methods, that could resolve what seems to be a messy situation in a clean manner. That said, your example doesn't demonstrate why it is fun()
is even being over-ridden, or what you hope to accomplish by sharing scope.
CodePudding user response:
There's no straightforward non-hacky way. (And I don't even know if there is a hacky way).
What you propose violates the encapsulation principle. A class hides its nitty gritty dirty internals and only exposes a neat interface with promised behavior.
Inheritance is not a mechanism to violate this principle.
In your concrete example, the issue comes from a bad interface design of T
. If T
had a method compute_a()
that would return self.p self.b
then in your inherited class you can of course call self.compute_a()
.
But only do this if a
is more than a mere internal implementation detail!
CodePudding user response:
You can simply return a value from fun()
in the parent class and then assign the returned value to a variable inside the child method. This certainly works but I don't think it's a good design:
class T:
def __init__(self, p, b):
self.p = p
self.b = b
self.fun()
def fun(self):
a = self.p self.b
return a
class TT(T):
def __init__(self, p, b):
super().__init__(p, b)
def fun(self):
a = super().fun()
c = self.p * self.b * a
return c
t = T(2, 3)
tt = TT(2, 3)
print(t.fun()) # >> 5
print(tt.fun()) # >> 30