1

I am trying to write a decorator for a method that will call a second method. When I run the code I receive the error:
AttributeError: 'Backoff' object has no attribute 'formatter'

Simplified, the code is:

class Backoff:
    def __init__(self, f):
        self.f = f

    def __call__(self, *args, **kwargs):
        n = 1
        while n < 11:
            try:
                return self.f(self, *args, **kwargs)
            except FooError as e:
                <handle error>
                time.sleep((2 ** n) + (random.randint(0, 1000) / 1000))
                n = n + 1

class SomeClass:
    def __init__(self):
        pass
    @Backoff
    def first_method(self, foo, bar):
        return self.formatter(foo, bar)

    def formatter(self, x, y):
        return some_function_to_format(x, y)

How can I pass the second method to the first method in a way that the decorator can recognise it?

Any help would be amazing!

  • 1
    You init methods lacks the self argument. Possibly the same for formatter. – Olivier Melançon Jun 08 '18 at 02:04
  • @jedwards i received an error saying I had the wrong number of arguments prior to adding self. I didn't think it was necessary either initially – Matthew Cranley Jun 08 '18 at 02:12
  • @OlivierMelançon the original code had the self argument in both methods, but my quick transcribing into StackOverflow and I dropped them by mistake. Code is edited – Matthew Cranley Jun 08 '18 at 02:15
  • Could you provide code that can run, the except statement disallows me to copy-paste your code and run it without a SyntaxError. Make sure to read how to create a [Minimal Verifiable Example](https://stackoverflow.com/help/mcve) before asking please, it helps us helping you! – Olivier Melançon Jun 08 '18 at 02:21
  • 1
    [Here's an outstanding answer to a similar question](https://stackoverflow.com/a/30105234/736937), describing your issue, the problem, and how to solve it. – jedwards Jun 08 '18 at 02:34

1 Answers1

2

You are passing a method to Backoff, assigning it as an instance variable, and then calling it. This not bound to an instance until it is being called in Backoff.__call__, where it is then bound to an instance of Backoff which does not have a formatter property.

There might be a straightforward solution to this depending on what your instance method needs access to (i.e. if it only needs to reference a class or static method, it can just call the fully qualified name directly). However, if you need the instance method to reference an instance property, I would suggest not using a class decorator at all. Using a function decorator will not run into these issues, you can create a closure and return a function with the same call signature.

Jared Goguen
  • 8,772
  • 2
  • 18
  • 36