Home > Net >  Keep local variables in scope when extending a method
Keep local variables in scope when extending a method

Time:10-05

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() becomes a = 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

  • Related