Metaclass __new__ return value

Good morning,

I am looking at the test_set_name_metaclass test: the metaclass in this test has __new__ method which returns 0, instead of a class. Is that supposed to work or does it just happen to work? Reading the docs, I don’t see them saying that __new__ must return a class, but it seems to be implied. In particular, __class__ cell will be set to that value, so if the class in question happens to use super or some such then that will just bomb at runtime.
(My real question is: if an implementation raises an error in this case because __new__ returned something that isn’t a class, then does this implementation still count as Python?)

__new__ returns a class instance; often referred to as an object, or object instance. It is clearly stated in the docs:

The return value of __new__() should be the new object instance (usually an instance of cls ).

BTW, the mock __new__ method probably returns 0 (or «an int instance which holds the value 0») because of test verification convenience :slight_smile:

Note that the usage in the test is a bit weird, as it does

class A(metaclass=Meta):
    d = Descriptor()
self.assertEqual(A, 0)

So A (the object created by the class statement) is checked to be equal to 0 (an integer). Which it is, because that’s what Meta.__new__ returns.

The point of the test is to make sure that __set_name__ is called at the right point, so the fact that A isn’t actually a class (an instance of type) is irrelevant here.

IMO, it’s legal for __new__ to return an arbitrary object. It’s unusual, and obfuscated, but I’ve seen people (ab)use class statements to do “weird stuff”, and while I wouldn’t necessarily want to see that in my production code, it’s legitimate Python.

1 Like

test_set_name_metaclass is fine. Yes, it is supposed to work.

I don’t know if this is documented anywhere, but I know it is allowed
because it is used by the reference implementation, CPython.

It is also permitted by PyPy3. I have not bothered to check IronPython
or Jython as they are only supporting Python 2.

The Python language does not enforce normal metaclass behaviour, it
merely assumes that a normal metaclass __new__ method should return a
class object in the common case. But metaclasses can return anything.
They don’t even have to be a class, any callable will do!

def meta(*args):
    return "Spam spam spam lovely spam"

class X(metaclass=meta):
    pass

assert X == 'Spam spam spam lovely spam'

Is this useful? Maybe. Is it allowed? Absolutely.

Are you permitted to write a Python implementation that is stricter in
what it allows? Of course you can, but whether that would still count as
“Python”, or a different language, is a subjective question. I think you
would have to ask Guido and the Steering Council.

My guess is that if the only difference is that your Python
interpreter enforces that metaclasses only return classes, they would
probably allow it. MicroPython has many differences from CPython, but it
is still considered Python.

Why do you want to enforce that in the interpreter?

Yes, it is intentional. You could write a metaclass that returns something that is a duck type for a class, e.g. a function returning mock instances.

It’s not that I want to, I just happened to have done it and then the test failed, and it wasn’t obvious who was wrong. Well, given that it’s a CPython test, it’s rather obvious, but still :slight_smile:

Guido’s comment about mocks makes perfect sense, it didn’t occur to me to jump from seemingly obviously useless/wrong zero to something fancier/more meaningful. And I suppose there is some really interesting stuff that can be implemented using a class body which doesn’t actually become a class.