Michael
Michael

Reputation: 443

Spurious arguments to __new__ when using metaclass

I am trying to learn about metaclasses in python 3.7 and have the following code

class Foo(type):

    def __new__(cls, *args, **kwargs):
        return super().__new__(cls, *args, **kwargs)

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

    def __call__(cls, *args, **kwargs):
        return super().__call__(cls, *args, **kwargs)


class Bar(metaclass=Foo):

    def __new__(cls, *args, **kwargs):
        print(cls)
        print(args)
        print(kwargs)
        return super().__new__(cls, *args, **kwargs)

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


b = Bar()

When I run it I get the output

<class '__main__.Bar'>
(<class '__main__.Bar'>,)
{}

and the error

File "meta/main.py", line 91, in __new__
    return super().__new__(cls, *args, **kwargs)
TypeError: object.__new__() takes no arguments

where the line correpondse to the __new__ call in Bar

I can't work out why the second <class '__main__.Bar'> is being passed in. If I change Bar to not use the Foo metaclass (i.e. change class Bar(metaclass=Foo): to class Bar:) I get

<class '__main__.Bar'> 
()
{}

and no errors (as I would expect). Thanks for any help

Upvotes: 1

Views: 43

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1121714

You are passing in an extra argument on calls:

def __call__(cls, *args, **kwargs):
    return super().__call__(cls, *args, **kwargs)

__call__ is not an implicit static method, drop that cls argument:

def __call__(cls, *args, **kwargs):
    return super().__call__(*args, **kwargs)

Upvotes: 2

Related Questions