On 2019-12-31 4:28 p.m., Andrew Barnert wrote:
On Dec 31, 2019, at 11:02, Soni L. <fakedme...@gmail.com> wrote:
> > >> On 2019-12-31 3:56 p.m., Andrew Barnert wrote:
>> On Dec 31, 2019, at 09:43, Soni L. <fakedme...@gmail.com> wrote:
>> > > I would like this code to work, but currently python ignores 
__subclasscheck__ in many places where it checks for subclasses:
>> > > class MM(type):
>> >     def __subclasscheck__(self, subclass):
>> >         return issubclass(subclass, type)
>> > > > class M(type, metaclass=MM):
>> >     pass
>> > > > class N(type):
>> >     pass
>> > > > class C(metaclass=M):
>> >     pass
>> > > > class D(metaclass=N):
>> >     pass
>> > > > class E(C, D, metaclass=N):
>> >     pass
>> >> Is the problem you’re trying to solve here, that you want to be able to override the metaclass conflict check in class definitions, so you can allow this? >> >> If so, I think it makes sense. N is (trivially) a subclass of the N (the metaclass of D), and you’re making it a virtual subclass (via MM) of M (the metaclass of C). So there actually is no conflict if you take virtual subclasses into account; N is unambiguously the most derived metaclass. >> >> (I suppose it would be ambiguous again if you also made M a (virtual or direct) subclass of N, but that’s probably consulting-adults territory: don’t do that, and if you do, the fact that the error message isn’t as meaningful as it could be isn’t a huge deal.) >> >> But you said “many places”. Is there a wider class of places, that includes the metaclass conflict check, where virtual subclassing is ignored but (you think) shouldn’t be? > > In the documentation for metaclass stuff, Python mentions "subtype" without referring to issubtype. I assume other parts of the docs also do similar things, but I haven't checked.

Well, there is no “issubtype”; only “issubclass”. Just like there is no 
“virtual subtype”, only “virtual subclass”.

I think the docs may be deliberately using “subtype” rather than “subclass” for 
that reason. But if so, it isn’t exactly clear, because I don’t think “subtype” 
is actually defined anywhere, and “direct or indirect, but not virtual, 
subclass” certainly isn’t the only meaningful guess you could make. This is 
probably worth filing a docs bug on even if nothing else is changed to clarify 
what that’s supposed to mean. (With your change, the docs probably just need to 
change to say subclass.)

I only see the word “subtype” a few other times, and they’re all declaring that 
some builtin is a subtype or some other thing, so it doesn’t matter whether 
it’s supposed to mean “subclass” or “non-virtual subclass” or some other thing. 
But I haven’t searched exhaustively.

But meanwhile, even if you do fix this here, would it actually help? It would 
mean the interpreter can determine the most derived metaclass unambiguously, so 
it would call N.__prepare__ and eventually N('E', (C, D), {…stuff…}). Which 
would be fine if you overrode __new__ or meta __call__ or didn’t inherit from 
type, but you don’t do any of those, so that just calls type.__new__. And 
(again, I haven’t tested any of this…) doesn’t type.__new__ also need to work 
out the most derived subtype again? Or does that already work?

And then, even if that works, wouldn’t that make it do things like call 
N.__init_subclass__(C) instead of type(C).__init_subclass__(C)? (That’s an 
abbreviation for the special method lookup rules, not literal code. And again, 
I haven’t tested any of this, so maybe I’m being stupid.)

Why would it call N.__init_subclass__(C), or type(C).__init_subclass__(C) for that matter? __init_subclass__ goes on the baseclass, not metaclass.

And uh, I don't think customizing the actual class instance for the parent class means you can't drop that customization for child classes. For what it's worth, I do want to override meta __call__ actually, and only that. Only because, currently, you can't just override __new__ as it'd lead to __init__ being called twice for e.g. the E() in M(E()), if you wanted to return it from __new__ for some reason.

How can you have multiple inheritance, and have a magic __call__ on the parent class (but not keep it - or at least not keep its behaviour, if no metaclass is explicitly specified - for subclasses)? Currently it doesn't seem like you can.

> However, I can imagine cases where virtual subtypes would cause problems. 
Namely, the C API and builtins. But, more importantly, it wouldn't work there 
anyway since you can't monkeypatch __instancecheck__ / __subclasscheck__ of 
built-ins in the first place.

I didn’t think of that. But you don’t have to monkeypatch them to hot that 
problem, you can write your own extension module with a class that defines 
__subclasscheck__, and what happens then? (Although consenting adults seems 
even more relevant here—as long as the answer isn’t “segfault without 
diagnostics”, whatever happens is probably fine…)


_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/WQ3N6THEEFP5J7TI53VW23K5CT5CZCON/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to