This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author Takuo Matsuoka
Recipients Takuo Matsuoka, ethan.furman, steven.daprano
Date 2022-04-05.11:04:35
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1649156675.32.0.585034682716.issue47136@roundup.psfhosted.org>
In-reply-to
Content
Thank you Ethan for reopening this issue and closing the other one.

Here is a description of a more specific issue, containing a more
reasonable example.  I've changed the title of the issue to a more
appropriate one accordingly.

Context
-------
Some classes have the variable __name__ in their namespace __dict__ ,
and one may wish to create more such classes with varied values of
__name__ .  Some of those could be created with a metaclass whose
__prepare__ returns a mapping having key "__name__", for which the
value is created depending on the arguments of __prepare__ and can be
updated or deleted in the body of the class to be created.  (See C
below for a very silly example of such a metaclass.)


Problem
-------
The value of __name__ given by __prepare__ becomes not just that in
the class body, but automatically also the value of __module__
there.  As far as I could see, this is not documented, and the
programmer might not notice __module__ was messed up.  I think this
behaviour is unexpected and problematic at least unless a warning is
given on it in the document.

Also, the problem means we can't safely enjoy the ability of
__prepare__ of a metaclass to give a candidate for the value of
__name__ in __dict__ of the class without the trouble of fixing the
variable __module__ later at the top of the class body for every
instance of the metaclass (very annoying) somehow (or in __new__ or
__init__ of the metaclass if __module__ is not to be read in the class
body).


Example
-------
Here's a code which produces a problem.

```
# In this example, the metaclass C is intended to be a class of
# subclasses of:
B = type

class C(type(B)):
    @classmethod
    def __prepare__(cls, /, *args, **kwargs):
        return dict(__name__ = cls._name(*args, **kwargs))
    @classmethod
    def _name(cls, /, *args, **kwargs):
        # The actual value of __name__ doesn't matter much to the
        # issue, so I make this function always return the same silly
        # thing in this example.
        return type.__dict__["__name__"]

class O(B, metaclass=C):
    print(__module__ == __name__) # True
    # Could update or delete __name__ here.
```

Consequently,

>>> O.__module__
<attribute '__name__' of 'type' objects>


Thanks.

P.S.
The argument mentioning "the scope outside" in my earlier post here
didn't make sense without specifying which scope.  I still hope the
problem can be fixed.
History
Date User Action Args
2022-04-05 11:04:35Takuo Matsuokasetrecipients: + Takuo Matsuoka, steven.daprano, ethan.furman
2022-04-05 11:04:35Takuo Matsuokasetmessageid: <1649156675.32.0.585034682716.issue47136@roundup.psfhosted.org>
2022-04-05 11:04:35Takuo Matsuokalinkissue47136 messages
2022-04-05 11:04:35Takuo Matsuokacreate