Toothpick Anemone
Toothpick Anemone

Reputation: 4644

Arguments disappear from callable object

Suppose you have a function with multiple arguments:

def foo(x1, x2, x3, y):
    pass

I am trying to make a class, named FAI, behave a little like the functools.partial function.

bar = my_class(foo, 1, 2, 3)
bar("a")
# `bar("a")` supposed to be the same as `foo(1, 2, 3, "a")` 

When I run the following code:

def bar(*args):
    print(args)

bar = FAI(bar, 1)
bar = FAI(bar, 2)
bar = FAI(bar, 3)
bar = FAI(bar, 4)
bar = FAI(bar, 5)
bar = FAI(bar, 6)

bar("a", "b", "c")

The sys.stdout output I get is:

(1, 'a', 'b', 'c')

The desired output is one of the following:

(1, 2, 3, 4, 5, 6, 'a', 'b', 'c')
(6, 5, 4, 3, 2, 1, 'a', 'b', 'c')

How do I get the desired output?

import functools
import inspect

class Meta(type):
    functools=functools
    inspect=inspect
    def __call__(self, imp, *args, **kwargs):
        """
        instance = Klass(imp)
        instance = Klass.__call__(imp)
        instance = Meta.__call__(Klass, imp)
        """
        # `imp`.......`implementation`
        Meta = type(self)
        SuperMeta = Meta.inspect.getmro(Meta)[1]
        inst = SuperMeta.__call__(self, imp, *args, **kwargs)
        inst = functools.update_wrapper(wrapper=inst, wrapped=imp)
        return inst # instance

class FAI(metaclass=Meta):
    """
    `FAI`..........`First argument inputter`
    """
    def __init__(self, imp, arg):
        # `imp`.......`implementation`
        assert (callable(imp))
        self._arg = arg
        self._imp = imp

    def __call__(self, *args, **kwargs):
        return self._imp(self._arg, *args, **kwargs)

Upvotes: 0

Views: 51

Answers (1)

user2357112
user2357112

Reputation: 280456

You're using functools.update_wrapper. You shouldn't. It's designed to work with functions of the type defined by def, not arbitrary callables.

Your update_wrapper is copying the _arg and _imp attributes from old FAI instances to new ones, so the last one has the first one's _arg and _imp.

Also, your Meta.__call__ has the most bizarrely manual implementation of the super(type(self), self) bug I've seen yet. If you ever create a subclass of Meta (which can happen without you even noticing, if you don't understand the libraries you use), SuperMeta will be Meta itself or some other wrong class. Use super().__call__(imp, *args, **kwargs) there.

Upvotes: 1

Related Questions