<div dir="auto">Please keep in mind that this idea was not created to improve monkey patching, it just happens to be one of the side effects due to classes being objects. The main use case is the ability to set an instance's callback function (see the Menu example), and to allow the class being referenced in the function's header; for example in a decorator and during typing.<div dir="auto"><br></div><div dir="auto">No additional "fancy" features are intended, it would simply replace this:</div><div dir="auto"><br></div><div dir="auto">    foo = Bar()</div><div dir="auto">    def f():</div><div dir="auto">        ...</div><div dir="auto">    foo.f = f</div><div dir="auto"><br></div><div dir="auto">With syntax sugar, similar to how decorators replaced this:</div><div dir="auto"><br></div><div dir="auto">    def f():</div><div dir="auto">        ...</div><div dir="auto">    f = decorate(f)</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Feb 10, 2017 20:50, "Nick Timkovich" <<a href="mailto:prometheus235@gmail.com">prometheus235@gmail.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">If everything was contained right in the same file, this is sanctioning another way to do it (when there should only be one obvious way). If you have multiple modules/packages, horrors can evolve where a class method could be patched in an unknown location by any loaded module (or you could even introduce order-of-import sensitivities). <div><br></div><div>For testing, this can be a necessary evil which is OK so long as the patch is limited/apparent, and some other very narrow cases (setuptools something something?). That said, I don't want their use condoned or eased for fear of proliferation of these "antiprogrammer land mines" that I might trip over in the future.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Feb 10, 2017 at 12:15 PM, Joshua Morton <span dir="ltr"><<a href="mailto:joshua.morton13@gmail.com" target="_blank">joshua.morton13@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">One thing that I don't think has been mentioned, but that brings me from a +0 to a more negative outlook, is the interaction between this proposal and some of python's existing class-related features, metaclasses and descriptors. That is currently we know that function definition, and even method definition, will not have side effects. This potentially changes that since<div><br></div><div>    def Foo.foo(self):</div><div>        ...</div><div><br></div><div>could be a descriptor. Even if it doesn't, its possible that `Foo.foo` is actually resolved from `Foo._foo`, and so this potentially further confuses the naming considerations.</div><div><br></div><div>Then we have metaclasses. Prior to this change, it would be fully the monkeypatcher's responsibility to do any metaclass level changes if they were necessary when monkeypatching. However, since we are potentially adding a first class support for certain monkeypatches, It raises a question about some first class way to handle monkeypatched methods. Do we need to provide some kind of method to a metaclass writer that allows them to handle methods that are patched on later? Or does the language still ignore it?</div><div><br></div><div>--Josh</div></div><div class="m_962347978087283664HOEnZb"><div class="m_962347978087283664h5"><br><div class="gmail_quote"><div dir="ltr">On Fri, Feb 10, 2017 at 12:20 PM Nick Coghlan <<a href="mailto:ncoghlan@gmail.com" target="_blank">ncoghlan@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 10 February 2017 at 16:25, Steven D'Aprano <<a href="mailto:steve@pearwood.info" class="m_962347978087283664m_5121958161727101795gmail_msg" target="_blank">steve@pearwood.info</a>> wrote:<br class="m_962347978087283664m_5121958161727101795gmail_msg">
> On Sat, Feb 11, 2017 at 01:25:40AM +1100, Chris Angelico wrote:<br class="m_962347978087283664m_5121958161727101795gmail_msg">
><br class="m_962347978087283664m_5121958161727101795gmail_msg">
>> For what it's worth, my answers would be:<br class="m_962347978087283664m_5121958161727101795gmail_msg">
>><br class="m_962347978087283664m_5121958161727101795gmail_msg">
>> __name__ would be the textual representation of exactly what you typed<br class="m_962347978087283664m_5121958161727101795gmail_msg">
>> between "def" and the open parenthesis. __qualname__ would be built<br class="m_962347978087283664m_5121958161727101795gmail_msg">
>> the exact same way it currently is, based on that __name__.<br class="m_962347978087283664m_5121958161727101795gmail_msg">
><br class="m_962347978087283664m_5121958161727101795gmail_msg">
> If I'm reading this right, you want this behaviour:<br class="m_962347978087283664m_5121958161727101795gmail_msg">
><br class="m_962347978087283664m_5121958161727101795gmail_msg">
> class Spam:<br class="m_962347978087283664m_5121958161727101795gmail_msg">
>     pass<br class="m_962347978087283664m_5121958161727101795gmail_msg">
><br class="m_962347978087283664m_5121958161727101795gmail_msg">
> def Spam.func(self): pass<br class="m_962347978087283664m_5121958161727101795gmail_msg">
><br class="m_962347978087283664m_5121958161727101795gmail_msg">
> assert 'Spam.func' not in Spam.__dict__<br class="m_962347978087283664m_5121958161727101795gmail_msg">
> assert 'func' in Spam.__dict__<br class="m_962347978087283664m_5121958161727101795gmail_msg">
><br class="m_962347978087283664m_5121958161727101795gmail_msg">
> assert Spam.func.__name__ == 'Spam.func'<br class="m_962347978087283664m_5121958161727101795gmail_msg">
> assert Spam.func.__qualname__ == 'Spam.Spam.func'<br class="m_962347978087283664m_5121958161727101795gmail_msg">
><br class="m_962347978087283664m_5121958161727101795gmail_msg">
> If that's the case, I can only ask... what advantage do you see from<br class="m_962347978087283664m_5121958161727101795gmail_msg">
> this? Because I can see plenty of opportunity for confusion, and no<br class="m_962347978087283664m_5121958161727101795gmail_msg">
> advantage.<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
What I would personally hope to see from the proposal is that given:<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
    class Spam:<br class="m_962347978087283664m_5121958161727101795gmail_msg">
        pass<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
    def Spam.func(self):<br class="m_962347978087283664m_5121958161727101795gmail_msg">
        return __class__<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
the effective runtime behaviour would be semantically identical to:<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
    class Spam:<br class="m_962347978087283664m_5121958161727101795gmail_msg">
        def func(self):<br class="m_962347978087283664m_5121958161727101795gmail_msg">
            return __class__<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
such that:<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
  * __name__ is set based on the method name after the dot<br class="m_962347978087283664m_5121958161727101795gmail_msg">
  * __qualname__ is set based on the __name__ of the given class<br class="m_962347978087283664m_5121958161727101795gmail_msg">
  * __set_owner__ is called after any function decorators are applied<br class="m_962347978087283664m_5121958161727101795gmail_msg">
  * zero-argument super() and other __class__ references work properly<br class="m_962347978087283664m_5121958161727101795gmail_msg">
from the injected method<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
Potentially, RuntimeError could be raised if the reference before the<br class="m_962347978087283664m_5121958161727101795gmail_msg">
dot is not to a type instance.<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
If it *doesn't* do that, then I'd be -1 on the proposal, since it<br class="m_962347978087283664m_5121958161727101795gmail_msg">
doesn't add enough expressiveness to the language to be worth the<br class="m_962347978087283664m_5121958161727101795gmail_msg">
extra syntax. By contrast, if it *does* do it, then it makes class<br class="m_962347978087283664m_5121958161727101795gmail_msg">
definitions more decomposable, by providing post-definition access to<br class="m_962347978087283664m_5121958161727101795gmail_msg">
parts of the machinery that are currently only accessible during the<br class="m_962347978087283664m_5121958161727101795gmail_msg">
process of defining the class.<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
The use case would be to make it easier to inject descriptors when<br class="m_962347978087283664m_5121958161727101795gmail_msg">
writing class decorators such that they behave essentially the same as<br class="m_962347978087283664m_5121958161727101795gmail_msg">
they do when defined in the class body:<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
    def my_class_decorator(cls):<br class="m_962347978087283664m_5121958161727101795gmail_msg">
        def cls.injected_method(self):<br class="m_962347978087283664m_5121958161727101795gmail_msg">
            # Just write injected methods the same way you would in a class body<br class="m_962347978087283664m_5121958161727101795gmail_msg">
            return __class__<br class="m_962347978087283664m_5121958161727101795gmail_msg">
        return cls<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
(Actually doing this may require elevating super and __class__ to true<br class="m_962347978087283664m_5121958161727101795gmail_msg">
keyword expressions, rather than the pseudo-keywords they are now)<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
Cheers,<br class="m_962347978087283664m_5121958161727101795gmail_msg">
Nick.<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<br class="m_962347978087283664m_5121958161727101795gmail_msg">
--<br class="m_962347978087283664m_5121958161727101795gmail_msg">
Nick Coghlan   |   <a href="mailto:ncoghlan@gmail.com" class="m_962347978087283664m_5121958161727101795gmail_msg" target="_blank">ncoghlan@gmail.com</a>   |   Brisbane, Australia<br class="m_962347978087283664m_5121958161727101795gmail_msg">
______________________________<wbr>_________________<br class="m_962347978087283664m_5121958161727101795gmail_msg">
Python-ideas mailing list<br class="m_962347978087283664m_5121958161727101795gmail_msg">
<a href="mailto:Python-ideas@python.org" class="m_962347978087283664m_5121958161727101795gmail_msg" target="_blank">Python-ideas@python.org</a><br class="m_962347978087283664m_5121958161727101795gmail_msg">
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" class="m_962347978087283664m_5121958161727101795gmail_msg" target="_blank">https://mail.python.org/mailma<wbr>n/listinfo/python-ideas</a><br class="m_962347978087283664m_5121958161727101795gmail_msg">
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" class="m_962347978087283664m_5121958161727101795gmail_msg" target="_blank">http://python.org/psf/codeofco<wbr>nduct/</a><br class="m_962347978087283664m_5121958161727101795gmail_msg">
</blockquote></div>
</div></div><br>______________________________<wbr>_________________<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/mailma<wbr>n/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofco<wbr>nduct/</a><br></blockquote></div><br></div>
<br>______________________________<wbr>_________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/<wbr>mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/<wbr>codeofconduct/</a><br></blockquote></div></div>