Search code examples
pythoninheritancesignature

Accessing signatures of overriding methods in subclasses


In python3.8.5, I am working with an existing class superClthat defines a method f, and multiple existing subclasses sub1, sub2... that override f with different numbers of variables. Based on How to create new subclasses by adding the same method to multiple classes, I would like to add a new function gto all subclasses via the superclass. The new function should call fand do things with it. The problem is that each subclass has a different signature for f. How can I get around that? Sample code follows:

import numpy as np

class superCl(object): # Exists already
    def f(self, x): return x

class sub1(superCl): # Exists already
    def f(self, x, a, b): return x / (b - a)
        
class sub2(superCl): # Exists already
    def f(self, x, tau): return 1/tau * np.exp(-x/tau)
        
sc = superCl()
print(sc.f(0))

s1 = sub1()
print(s1.f(0, 1, 2))

s2 = sub2()
print(s2.f(0, 1))

def g(self, x1, x2, ...): # New, calls existing method.  Is there some way to get the signatures and values from the subclasses, eg self.args?
    print('Extra meth')
    self.f(x1, ...) - self.f(x2, ...) # How to adapt to proper arguments for f for each sublcass?

superCl.g = g # New method gets added to new and existing instances

print(sc.g(0, 1))
print(s1.g(0, 1, 1, 2))
print(s2.g(0, 1, 1))

EDIT: Superclass defines a generic set of functions; subclasses are particular cases, each with different variables. Function freturns value of function for subclasses parameters; function g I am trying to create evaluates the difference in f at two different points.


Solution

  • Looks like using *args or **kwdsdoes it (Positional argument v.s. keyword argument):

    import numpy as np
    
    class superCl(object): # Exists already
        def f(self, x): return x
    
    class sub1(superCl): # Exists already
        def f(self, x, a, b): return x / (b - a)
            
    class sub2(superCl): # Exists already
        def f(self, x, tau): return 1/tau * np.exp(-x/tau)
            
    sc = superCl()
    print(sc.f(0))
    
    s1 = sub1()
    print(s1.f(0, 1, 2))
    
    s2 = sub2()
    print(s2.f(0, 1))
    
    print('===========================================')
    def g(self, x1, x2, *args): 
        print("args", *args)
        return self.f(x2, *args) - self.f(x1, *args)
    superCl.g = g
    print("--------------------\n"); print("sc", sc.f(1), '-', sc.f(0), "=", sc.g(0, 1))
    print("--------------------\n"); print("s1", s1.f(1, 0, 4), '-', s1.f(0, 0, 4), "=", s1.g(0, 1, 0, 4))
    print("--------------------\n"); print("s2", s2.f(1, 5), '-', s2.f(0, 5), "=", s2.g(0, 1, 5))
    
    print('===========================================')
    def h(self, x1, x2, **args): 
        print("args", args)
        return self.f(x2, **args) - self.f(x1, **args)
    superCl.h = h
    print("--------------------\n"); print("sc", sc.f(1), '-', sc.f(0), "=", sc.h(0, 1))
    print("--------------------\n"); print("s1", s1.h(0, 1, a=0, b=4))
    print("--------------------\n"); print("s2", s2.h(0, 1, tau=5))