6

In the following example, the newly created subclass ends up being the metaclass __module__ rather than the parent classes' module. I've only seen this happen when using ABCMeta so it could be something specific to that module, anyone know what might be happening?

In [1]: from abc import ABCMeta

In [2]: class test(metaclass=ABCMeta):
   ...:     pass
   ...: 

In [3]: newclass = type('newclass', (test,), {})

In [4]: newclass.__module__
Out[4]: 'abc'

The behavior I want happens when I define the subclass in the more standard way:

In [5]: class subtest(test):
   ...:     pass
   ...: 

In [6]: subtest.__module__
Out[6]: '__main__'

Can someone explain why this is the case and how you could, using type, create a new subclass with the correct __module__ attribute inherited (e.g. __module__=='__main__')?

1
  • 1
    This looks like it might be an actual bug. Very interesting. Commented Mar 23, 2018 at 20:03

1 Answer 1

7

If no __module__ key is present in the mapping passed to type.__new__, type.__new__ determines __module__ based on the module where the call to type.__new__ occurs, by looking for __name__ in the globals of the top Python stack frame.

When you run newclass = type('newclass', (test,), {}), the type constructor delegates to abc.ABCMeta, which then calls type.__new__ from inside the abc module, so type thinks that __module__ should probably be abc.

When you write the class statement

class subtest(test):
    pass

The compiled bytecode for the class statement automatically includes a __module__ = __name__ assignment, which uses the current module's __name__ instead of abc.__name__.

If you want to control the value of __module__ for a class created by calling type directly, you can set the key in the original mapping, or assign to the class's __module__ after creation:

newclass = type('newclass', (test,), {'__module__': __name__})

# or

newclass = type('newclass', (test,), {})
newclass.__module__ = __name__
Sign up to request clarification or add additional context in comments.

5 Comments

@wim. I'd imagine it's no more dangerous than allowing abc.ABCMeta to set it for you implicitly.
@wim. Do __name__ = 'asdfsdaasdasd' in the shell, then check the __module__ of any new class you make, either with class or type. Fun stuff.
@wim: Answer expanded.
Good, +1. Do you think there is any possible difference in the newclass depending on whether it received __module__ from the namespace passed into type vs setting it afterward?
@wim: I don't think either type or abc.ABCMeta would have a problem with it, but if some other metaclass wants to use __module__ at type creation time, it's going to need __module__ in the original mapping. Also, if some code somehow gets access to the class object between creating it and reassigning its __module__, that code could see the original value of __module__.

Your Answer

Draft saved
Draft discarded

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.