<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Tue, Jul 19, 2016 at 7:51 AM Steven D'Aprano <<a href="mailto:steve@pearwood.info">steve@pearwood.info</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Tue, Jul 19, 2016 at 03:18:34PM +1000, Nick Coghlan wrote:<br>
<br>
> On 19 July 2016 at 14:04, Guido van Rossum <<a href="mailto:guido@python.org" target="_blank">guido@python.org</a>> wrote<br>
in response to my comments:<br>
<br>
> > The same argument would apply against abstractmethod...<br>
<br>
Well, to be honest, I've never been in a situation where I either needed<br>
abstractmethod or knowingly had to deal with a class that used it.<br>
<br>
Maybe I just don't use classes enough to see why this proposal is<br>
useful.<br>
<br>
> > I have definitely<br>
> > wondered when looking over some code whether it was defining or overriding a<br>
> > method.<br>
<br>
Isn't that one of the features of IDEs?<br>
<br>
(Which doesn't help those who aren't using an IDE.)<br>
<br>
<br>
> > But requiring people to always decorate overrides seems hard, unless<br>
> > we made it a property that can be enforced by a metaclass, maybe?<br>
<br>
[Nick]<br>
> This is trickier in Python than it is in Java, since we support<br>
> multiple inheritance, and we don't require that subclasses be drop-in<br>
> replacements for their parent class.<br>
<br>
Indeed.<br>
<br>
<br>
> The key difference I see between @abstractmethod and this proposal is<br>
> that @abstractmethod is a service that base class authors provide to<br>
> subclass authors to say "Hey, when subclassing this, you *need* to<br>
> override these, or your subclass won't work properly". In effect, it's<br>
> an implicit test case for all future subclass definitions.<br>
><br>
> By contrast, this proposal would go in the other direction: it would<br>
> be an assertion by the author of a *subclass* that that particular<br>
> method isn't new, it's inherited from a parent class, and they're<br>
> replacing the existing implementation with a new one. It would only<br>
> add new information for readers in cases where the method wasn't<br>
> already calling super() (since the latter already implies you expect<br>
> there to be at least one further implementation along the MRO to<br>
> call).<br>
><br>
> In my view, that puts it more in the category of type annotations and<br>
> the "missing attribute" detection in tools like pylint than it does<br>
> abstractmethod: rather than checking it at runtime, you'd want static<br>
> checkers like mypy to flag it as a structural error if a method<br>
> declared as replacing a base class method wasn't actually doing so.<br>
<br>
Certainly this is something which static checkers *could* do, but surely<br>
a runtime check would be sufficient? The runtime check only needs to<br>
occur when the class is defined, not on every call. It could look<br>
something like this:<br>
<br>
def override(method):<br>
    proxy = get_class_proxy()  # MAGIC GOES HERE<br>
    assert hasattr(method.__name__, proxy)<br>
    return method<br>
<br>
I say MAGIC GOES HERE because of course the class doesn't exist yet. The<br>
get_class_proxy() function should return some sort of proxy to the<br>
soon-to-exist class' MRO.<br></blockquote><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
(Maybe this is harder to write than I thought.)<br>
<br></blockquote><div><br></div><div>I don't think you need any magic.  You can either do it like @abstractmethod whereby you put the logic in ABCMeta or given that PEP 487 has been accepted, put the logic in a plain old base class (ABCBase?) that has the logic in __init_subclass__.  This would work with your corner case.  It also is a bit more flexible.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Having it work at class definition time rather than compile-time means<br>
that it will work with odd corner cases like injected methods:<br>
<br>
class C:<br>
    pass<br>
<br>
...<br>
...<br>
C.method = something()<br>
<br>
class D(C):<br>
    @override<br>
    def method(self):<br>
        pass<br>
<br>
<br>
I wouldn't expect a purely static checker to necessarily realise that<br>
C.method exists, but there's no problem for the runtime check.<br>
<br>
<br>
> So a "typing.override" to complement "typing.overload" would make<br>
> sense to me, but a checked-at-runtime decorator wouldn't (doing it<br>
> that way would also let you put the override annotation in stub files<br>
> instead of directly in the code).<br>
<br>
<br>
<br>
--<br>
Steve<br>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
<br>
--<br>
<br>
---<br>
You received this message because you are subscribed to a topic in the Google Groups "python-ideas" group.<br>
To unsubscribe from this topic, visit <a href="https://groups.google.com/d/topic/python-ideas/V6sUaArzGC0/unsubscribe" rel="noreferrer" target="_blank">https://groups.google.com/d/topic/python-ideas/V6sUaArzGC0/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href="mailto:python-ideas%2Bunsubscribe@googlegroups.com" target="_blank">python-ideas+unsubscribe@googlegroups.com</a>.<br>
For more options, visit <a href="https://groups.google.com/d/optout" rel="noreferrer" target="_blank">https://groups.google.com/d/optout</a>.<br>
</blockquote></div></div>