1

I am trying to decorate an @abstractmethod in an abstract class (inherited by abc.ABC in Python 3.9)

As a MWE,

from abc import ABC, abstractmethod

class Block(ABC):

    def __init__(self,id=1):
        self.id=id

    @abstractmethod # the method I want to decorate
    def run(self):
        pass

    def store_id(self,fun): # the decorator I want to apply to run()
        def wrapper(fun):
            id=fun()
            self.id=id
            return id
        return wrapper

class Example(Block):

    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)

    def run(self):
        print("I am running")
        id=3
        return id

t=Example()
t.run()
print(t.id)

I would like to decorate run() so that the returned id can be stored in the object without the end user to hardcode it.

I looked for the solution to this problem, the most complete being this one.

The __init_subclass__ magic method seems to be my best shot of using the method store_id within Block to decorate run() after its concrete implementation.

However, if I override __init_subclass__ in Block like this:

def __init_subclass__(self):
        super().__init_subclass__()
        self.run = self.store_id(self.run)

I get a TypeError which I do not know how to fix: TypeError: store_id() missing 1 required positional argument: 'fun'.

Am I approaching this problem in the right way? Am I missing something fundamental a or is it something related to 'abc' type of classes?

gtn_brsc
  • 11
  • 1
  • Your `def store_id(self,fun)` function takes two arguments, but `self.store_id(self.run)` only passes a single argument. Note, `__init_subclass__` will be provided with the *class* as the first argument – juanpa.arrivillaga Apr 10 '21 at 22:00
  • 1
    Your decorator is fundamentally strange. Why is it a method? If it is meant to wrap a method, it would break it, probably. The `fun` parameter is shadowed inside the wrapper, which has its own `fun` parameter... which doesn't make any sense. – juanpa.arrivillaga Apr 10 '21 at 22:03
  • Hi @juanpa.arrivillaga , thanks for the feedback. My understanding is that store_id(x,y) is equivalent to x.store_id(y) in the context of class/instance method. As per the `__init_subclass__`, the syntax is the same as in [the cited thread](https://stackoverflow.com/questions/61615935/implementing-an-after-decorator-on-an-abstract-method). Where is my mistake? – gtn_brsc Apr 10 '21 at 23:00
  • Moreover, if this is the wrong way to go about doing what I need, do you know the correct way to do this? – gtn_brsc Apr 10 '21 at 23:03
  • But you have an instance method, but your `self` parameter *isn't an instance in `__init_subclass__` it is *the class*. So try just doing `Example.store_id(Example.run)` which is exactly what is happening inside `__init_subclass__` – juanpa.arrivillaga Apr 10 '21 at 23:25

0 Answers0