Home > Software design >  Using python generics and inheritance
Using python generics and inheritance

Time:06-07

I need to implement a bunch classes, that all need to do the same modification to the parent class. As a skilled C programmer, I would look for a template class. But this needs to be implemented in Python. Here I am a rookie. I found the "Generic" and has constructed this example to show the core in my problem. The real program is somewhat more complicated(using ReportLab to generate PDF documents). I need to subclass to benefit from the class framework, which leads me into trying to implement a Generic using inheritance.

The problem is that cannot understand how I can pass argument to the "super" class, which here I try to make a Generic.

First attempt:

super().__init__(*argv, **kwargs)

Second attempt:

super(G, self).__init__(*argv, **kwargs)

Third attempt:

T.__init__(*argv, **kwargs)

Here is the complete example:

from typing import Generic, TypeVar

class A():
    def __init__(self, i : int):
        self.i = i

    def draw():
        print(self.i)

class C():
    def __init__(self, s : str):
        self.s = s

    def draw():
        print(self.s)

T = TypeVar('T')


class G(Generic[T]):
    def __init__(self, *argv, **kwargs):
        super().__init__(*argv, **kwargs)
        
    def draw():
        # Here is some special going to happen
        super().draw()
        
        
gA = G[A](5)        
gB = G[B]('Hello')

gA.draw()
gB.draw()

The output that I get:

Traceback (most recent call last):
  File "<string>", line 34, in <module>
File "/usr/lib/python3.8/typing.py", line 729, in __call__
    result = self.__origin__(*args, **kwargs)
  File "<string>", line 28, in __init__
TypeError: object.__init__() takes exactly one argument (the instance to initialize)

CodePudding user response:

You have understood Python generics wrong. A Generic, say Generic[T], makes the TypeVar T act as whatever you provide the instance with.

I found this page to be very useful with learning Generics.

CodePudding user response:

typing.Generic is specifically for type annotations; Python provides no runtime concept equivalent to either:

  1. Template classes, or
  2. Function overloads by parameter count/type

The latter has extremely limited support from functools.singledispatch, but it only handles the type of one argument, and the runtime type-checking is fairly slow.

That said, you don't need a template-based class or a polymorphic inheritance hierarchy here; Python is perfectly happy to call draw on anything that provides a method of that actual name. The code you're writing here can just do:

a = A(5)
b = B('Hello')

a.draw()
b.draw()

with no use of G needed.

  • Related