I have one more thing to run by on the topic of metaclasses and the usage of Self in metaclasses: There have been concerns about allowing the use of `Self` in metaclasses as it may be confusing to which type `Self` is referring. I will present my point of view for allowing `Self` in metaclasses.
"Special cases aren't special enough to break the rules."
— Tim Peters in the Zen of Python.
In the rest of this PEP, we have `Self` stand for a type variable bound to the encapsulating class. But I ask why should a metaclass operate any differently to a normal class. Consider: ```py class MyMetaclass(type): def __new__(mcs, *args: Any) -> type[Self]: cls = super().__new__(mcs, *args) return cls def __mul__(cls, count: int) -> list[type[Self]]: return [cls] * count ``` This is different right? It's like a classmethod with its `cls` and `mcs` parameters. But if I rename the `cls`s to `self` and `mcs` to `cls`: ```py class MyNormalClass(type): def __new__(cls, *args: Any) -> Self: self = super().__new__(cls, *args) return self def __mul__(self, count: int) -> list[Self]: return [self] * count ``` this looks similar to the other examples we have in the PEP. Now I do agree there could initially be some confusion about what the type of `cls` is if it is called: ```py class MyMetaclass(type): def __new__(mcs, *args: Any) -> Self: cls = super().__new__(mcs, *args) return cls() def __mul__(cls, count: int) -> list[Self]: return [cls()] * count ``` (notice the call to `cls()`) It may not be immediately noticeable that the return type of `Self` here is incorrect. But if we rename some variables. ```py class MyNormalClass(type): def __new__(cls, *args: Any) -> Self: self = super().__new__(cls, *args) return self() def __mul__(self, count: int) -> list[Self]: return [self()] * count ``` It is much more apparent this is wrong. We are using `__call__` on our instance of `Self` in this case, [`type.__call__`](https://github.com/python/typeshed/blob/05cc30b8da576f882dff41ae31c281c859b6...) which returns `Any`, breaking the mental model we have and so should be flagged as invalid. Personally I think disallowing this would make typing more confusing for newbies and veterans alike as well as being inconsistent with everything else this PEP allows.