1

I experiment with metaclasses to generate the class with the custom special method - particularly, __call__. The generation of the class depends on the parameters the constructor was called with. I've faced a strange effect, simplified example is below:

def trick(self, *args, **kwargs):
    print "Works!"

class Test1Factory(type):
    def __new__(mcls, name, bases, namespace):
        namespace['__call__'] = trick
        return type.__new__(mcls, name, bases, namespace)


class Test1(object):
    __metaclass__ = Test1Factory

    def __init__(self, value):
        self._value = value


t1 = Test1(1)
t1() # "Works!"

It works, but it is not really useful, because there is no access to constructor arguments within __new__. type.__call__ should do the trick:

import types
class Test2Factory(type):
    def __call__(self, *args, **kwargs):
        obj = type.__call__(self, *args, **kwargs)
        setattr(obj, '__call__', types.MethodType(trick, obj, Test2))

        return obj

class Test2(object):
    __metaclass__ = Test2Factory

    def __init__(self, value):
        self._value = value

t2 = Test2(2)
t2.__call__() # "Works!"
t2() # TypeError: 'Test2' object is not callable

As far as I understand, instance() is similar to instance.__call__(), but it is not the case here. Using __new__ static method of the class does the same. I have a workaround that does not use metaclasses at all, but just want to understand the phenomena. Python version is 2.7.5

krvss
  • 126
  • 3

1 Answers1

0

The wrong assumption may be in “instance() is similar to instance.__call__()”, as __call__ is not looked up for in instance, but in instance's type. That is, the __call__ used is not that of instance, but that of instance.__class__ or type(instance).

Any __call__ attribute defined on the instance solely, may be accessed regularly as any other attribute, but will not be used when instance is called as in instance(). That's part of Python's semantic.

Try to define a __call__ both on an instance and on its type, and see what you get.

If I understand the question correctly, the question has the same background as another I had, and which gets an answer (summarized, with demonstrations by experiments, in the question's post) : “How do Python tell “this is called as a function”?”.

Community
  • 1
  • 1
Hibou57
  • 6,870
  • 6
  • 52
  • 56