-1

So I have the following decorator code

class Factory:

    def __init__(self, cls):
        self.cls = cls

    def __instancecheck__(self, inst):
        return isinstance(inst, self.cls)

    def Produce(self):
        return self.cls()

And the following class code

@Factory
class Foo:

    def __init__(self, arg):
        self.arg = arg

    def method(self): pass

Which works great. Allows me to do stuff like

Foo.Produce().method()

Instead of

instance = Foo()
instance.method()

But now I cant use the class constructor normally

Foo(arg)

Gives the exception 'Factory object is not callable'. My question is the following: How can I make a decorator that allows me to instantiate the decorated class using its constructor, but also allows me to use a function in the decorator?

Alternative ways I'd rather not use:

  1. Skip the constructor. Always use <Class>.Produce() (and use *args/**kwargs to make it abstract/reusable.
  2. Use setters in all the classes, and make them return self so they can be chained.
  3. Make a class containing the produce method and extend this class.
Jongware
  • 22,200
  • 8
  • 54
  • 100
Neo
  • 49
  • 6
  • 1
    You could implement `__call__` on `Factory`. – jonrsharpe Jul 14 '16 at 09:14
  • 2
    I'm not sure I understand the benefit of the `Produce` method. The "stuff" you show that it lets you do is equivalent to `Foo().method()` on the undecorated class. You don't need to bind the instance to a variable unless you want to (though usually you do). – Blckknght Jul 14 '16 at 09:18
  • @Blckknght I feel pretty stupid now. Was very educational tho. Java, C#, PHP all dont allow it. So I assumed it was the same for python. – Neo Jul 14 '16 at 12:24

2 Answers2

2

The exception is telling you all you need to know, just add a __call__ method:

class Factory:
    # ...

    def __call__(self, *args, **kwargs):
        return self.cls(*args, **kwargs)
filmor
  • 30,840
  • 6
  • 50
  • 48
-1

If all you want to do is to add a Produce function to the class, you can rewrite your decorator like this:

def Factory(cls):
    def Produce():
        return cls()
    cls.Produce= Produce # add the function to the class
    return cls
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149