Deprecating "instance method" class

During my investigations related to low-level function/method classes, I came across the "instance method" class. There is a C API for it: https://docs.python.org/3.7/c-api/method.html However, it's not used/exposed anywhere in CPython, except as _testcapi.instancemethod (for testing its functionality) This class was discussed at https://mail.python.org/pipermail/python-3000/2007-December/011456.html and implemented in https://bugs.python.org/issue1587 Reading that old thread, there are use cases presented related to classic classes, wrapping Kogut (http://kokogut.sourceforge.net/kogut.html) objects and Pyrex. But classic classes no longer exist and the latter two use cases aren't actually needed if you read the thread to the end. So there are no surviving use cases from that thread. Does anybody know actual use cases or any code in the wild using it? To me, the fact that it's only exposed in the C API is a good sign that it's not really useful. So, should we deprecate the instance method class? Jeroen.

On 04/04/2019 13.51, Jeroen Demeyer wrote:
During my investigations related to low-level function/method classes, I came across the "instance method" class. There is a C API for it: https://docs.python.org/3.7/c-api/method.html However, it's not used/exposed anywhere in CPython, except as _testcapi.instancemethod (for testing its functionality)
This class was discussed at https://mail.python.org/pipermail/python-3000/2007-December/011456.html and implemented in https://bugs.python.org/issue1587 Reading that old thread, there are use cases presented related to classic classes, wrapping Kogut (http://kokogut.sourceforge.net/kogut.html) objects and Pyrex. But classic classes no longer exist and the latter two use cases aren't actually needed if you read the thread to the end. So there are no surviving use cases from that thread.
Does anybody know actual use cases or any code in the wild using it? To me, the fact that it's only exposed in the C API is a good sign that it's not really useful.
You are drawing the wrong conclusion here. The feature was explicitly designed for C code and C API wrappers like swig and Cython to make adaption to Python 3 simpler. I implemented it when I removed unbound methods.
So, should we deprecate the instance method class?
I couldn't find any current code that uses PyInstanceMethod_New. Let's deprecate the feature and schedule it for removal in 3.10. Christian

On 2019-04-04 14:09, Christian Heimes wrote:
I couldn't find any current code that uses PyInstanceMethod_New. Let's deprecate the feature and schedule it for removal in 3.10.

On 2019-04-05 00:57, Greg Ewing wrote:
If it's designed for use by things outside of CPython, how can you be sure nothing is using it?
Of course I'm not sure. However: 1. So far, nobody in this thread knows of any code using it. 2. So far, nobody in this thread knows any use case for it. And if we end up deprecating and it was a mistake, we can easily revert the deprecation.

05.04.19 09:07, Jeroen Demeyer пише:
On 2019-04-05 00:57, Greg Ewing wrote:
If it's designed for use by things outside of CPython, how can you be sure nothing is using it?
Of course I'm not sure. However:
1. So far, nobody in this thread knows of any code using it.
2. So far, nobody in this thread knows any use case for it.
And if we end up deprecating and it was a mistake, we can easily revert the deprecation.
I have a use case. I did not know this before, but it can be used to implement accelerated versions of separate methods instead of the whole class. I'm going to use it to further optimize total_ordering. Thanks Josh Rosenberg for the tip.

On 2019-04-05 14:10, Serhiy Storchaka wrote:
it can be used to implement accelerated versions of separate methods instead of the whole class.
Could you elaborate? I'm curious what you mean.
I'm going to use it to further optimize total_ordering.
There are so many ways in which total_ordering is inefficient. If you really want it to be efficient, you should just implement it in C.

05.04.19 14:27, Jeroen Demeyer пише:
On 2019-04-05 14:10, Serhiy Storchaka wrote:
it can be used to implement accelerated versions of separate methods instead of the whole class.
Could you elaborate? I'm curious what you mean.
It is easy to implement a function in C. But there is a difference between functions implemented in Python and C -- the latter are not descriptors. They behave like static methods when assigned to a class attribute, i.e. there is no implicit passing of the "self" argument.
I'm going to use it to further optimize total_ordering.
There are so many ways in which total_ordering is inefficient. If you really want it to be efficient, you should just implement it in C.
Yes, this is what I want to do. I did not do this only because implementing method-like functions which which do not belong to concrete class implemented in C is not convention. But PyInstanceMethod_New() should help.

On 2019-04-05 15:13, Serhiy Storchaka wrote:
It is easy to implement a function in C.
Why does it need to be a PyCFunction? You could put an actual method descriptor in the class. In other words, use PyDescr_NewMethod() instead of PyCFunction_New() + PyInstanceMethod_New(). It's probably going to be faster too since the instancemethod adds an unoptimized extra level of indirection.
Yes, this is what I want to do. I did not do this only because implementing method-like functions which which do not belong to concrete class implemented in C is not convention.
Sure, you could implement separate methods like __gt__ in C, but that's still less efficient than just implementing a specific tp_richcompare for total_ordering and then having the usual wrapper descriptors for __gt__.

Let's stop here. This API is doing no harm, it's not a maintenance burden, clearly *some* folks have a use for it. Let's just keep it, okay? There are bigger fish to fry. On Fri, Apr 5, 2019 at 5:36 AM Jeroen Demeyer <J.Demeyer@ugent.be> wrote:
On 2019-04-05 15:13, Serhiy Storchaka wrote:
It is easy to implement a function in C.
Why does it need to be a PyCFunction? You could put an actual method descriptor in the class. In other words, use PyDescr_NewMethod() instead of PyCFunction_New() + PyInstanceMethod_New(). It's probably going to be faster too since the instancemethod adds an unoptimized extra level of indirection.
Yes, this is what I want to do. I did not do this only because implementing method-like functions which which do not belong to concrete class implemented in C is not convention.
Sure, you could implement separate methods like __gt__ in C, but that's still less efficient than just implementing a specific tp_richcompare for total_ordering and then having the usual wrapper descriptors for __gt__. _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/guido%40python.org
-- --Guido van Rossum (python.org/~guido)

On 05/04/2019 17.46, Guido van Rossum wrote:
Let's stop here. This API is doing no harm, it's not a maintenance burden, clearly *some* folks have a use for it. Let's just keep it, okay? There are bigger fish to fry.
Sounds good to me. My code is 12 years ago and I can't remember any complain. I have closed the BPO issue and PR.

On 2019-04-05 17:46, Guido van Rossum wrote:
This API is doing no harm, it's not a maintenance burden
What if the following happens? 1. For some reason (possibly because of this thread), people discover instancemethod and start using it. 2. People realize that it's slow. 3. It needs to be made more efficient, causing new code bloat and maintenance burden.
clearly *some* folks have a use for it.
I'm not convinced. I don't think that instancemethod is the right solution for functools.total_ordering for example. Jeroen.

On Fri, Apr 5, 2019 at 11:30 AM Jeroen Demeyer <J.Demeyer@ugent.be> wrote:
On 2019-04-05 17:46, Guido van Rossum wrote:
This API is doing no harm, it's not a maintenance burden
What if the following happens?
1. For some reason (possibly because of this thread), people discover instancemethod and start using it.
2. People realize that it's slow.
3. It needs to be made more efficient, causing new code bloat and maintenance burden.
Then we can consider improving the documentation if there are performance implications. But the point is if there's code out there already using it without issue then ripping it out of the C API is painful since we don't have nearly as good of a deprecation setup as we do in Python code. Not everything about the C APi is about performance. -Brett
clearly *some* folks have a use for it.
I'm not convinced.
OK, but as of right now others like me are convinced and we typically err on the side of backwards-compatibility in these kinds of situations. -Brett
I don't think that instancemethod is the right solution for functools.total_ordering for example.
Jeroen. _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/brett%40python.org

On 2019-04-05 21:58, Brett Cannon wrote:
Then we can consider improving the documentation if there are performance implications.
Sure, we could write in the docs something like "Don't use this, this is not what you want. It's slow and there are better alternatives like method descriptors". Should I do that (with better wording of course)?
since we don't have nearly as good of a deprecation setup as we do in Python code.
I don't get this. One can easily raise a DeprecationWarning from C code, there is plenty of code already doing that. Jeroen.

On Fri, Apr 5, 2019 at 1:11 PM Jeroen Demeyer <J.Demeyer@ugent.be> wrote:
On 2019-04-05 21:58, Brett Cannon wrote:
Then we can consider improving the documentation if there are performance implications.
Sure, we could write in the docs something like "Don't use this, this is not what you want. It's slow and there are better alternatives like method descriptors". Should I do that (with better wording of course)?
Up to you. Obviously help is always appreciated, just a question of who feels qualified to review the PR.
since we don't have nearly as good of a deprecation setup as we do in Python code.
I don't get this. One can easily raise a DeprecationWarning from C code, there is plenty of code already doing that.
True. I personally prefer compile-time warnings for that sort of thing, but you're right we can do it at the Python "level" with a raise of a DeprecationWarning on those instances.

05.04.19 15:33, Jeroen Demeyer пише:
On 2019-04-05 15:13, Serhiy Storchaka wrote:
It is easy to implement a function in C.
Why does it need to be a PyCFunction? You could put an actual method descriptor in the class. In other words, use PyDescr_NewMethod() instead of PyCFunction_New() + PyInstanceMethod_New(). It's probably going to be faster too since the instancemethod adds an unoptimized extra level of indirection.
PyDescr_NewMethod() takes PyTypeObject* which is not known at that moment. But maybe passing &PyBaseObject_Type will make a trick. I need to try.
Yes, this is what I want to do. I did not do this only because implementing method-like functions which which do not belong to concrete class implemented in C is not convention.
Sure, you could implement separate methods like __gt__ in C, but that's still less efficient than just implementing a specific tp_richcompare for total_ordering and then having the usual wrapper descriptors for __gt__.
At Python level we can monkeypatch __gt__, but not tp_richcompare. In any case, removing a C API is a large breakage, and it is better to avoid it unless that API is inherently broken.

05.04.19 20:56, Jeroen Demeyer пише:
On 2019-04-05 19:53, Serhiy Storchaka wrote:
At Python level we can monkeypatch __gt__, but not tp_richcompare.
Sure, but you're planning to use C anyway so that's not really an argument.
total_ordering monkeypatches the decorated class. I'm planning to implement in C methods that implement __gt__ in terms of __lt__ etc.

On 2019-04-07 09:48, Serhiy Storchaka wrote:
total_ordering monkeypatches the decorated class. I'm planning to implement in C methods that implement __gt__ in terms of __lt__ etc.
Yes, I understood that. I'm just saying: if you want to make it fast, that's not the best solution. The fastest would be to implement tp_richcompare from scratch (instead of relying on slot_tp_richcompare dispatching to methods).

So we're making pretty heavy use of PyInstanceMethod_New in our python binding library that we've written for a bunch of in house tools. If this isn't the best / correct way to go about adding methods to objects, what should we be using instead? On Sun, Apr 7, 2019 at 2:17 AM Jeroen Demeyer <J.Demeyer@ugent.be> wrote:
On 2019-04-07 09:48, Serhiy Storchaka wrote:
total_ordering monkeypatches the decorated class. I'm planning to implement in C methods that implement __gt__ in terms of __lt__ etc.
Yes, I understood that. I'm just saying: if you want to make it fast, that's not the best solution. The fastest would be to implement tp_richcompare from scratch (instead of relying on slot_tp_richcompare dispatching to methods). _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/robert.wd.white%40gmail.c...

On 2019-04-08 17:08, Robert White wrote:
So we're making pretty heavy use of PyInstanceMethod_New in our python binding library that we've written for a bunch of in house tools. If this isn't the best / correct way to go about adding methods to objects, what should we be using instead?
First of all, the consensus in this thread is not to deprecate instancemethod. Well, it depends what you mean with "adding methods to objects", that's vaguely formulated. Do you mean adding methods at run-time (a.k.a. monkey-patching) to a pre-existing class? And is the process of adding methods done in C or in Python? Do you only need PyInstanceMethod_New() or also other PyInstanceMethod_XXX functions/macros?

Just PyInstanceMethod_New, and by "adding methods to objects" this is adding C functions to types defined in C. Only appears to be called at module import / creation time. On Mon, Apr 8, 2019 at 10:24 AM Jeroen Demeyer <J.Demeyer@ugent.be> wrote:
On 2019-04-08 17:08, Robert White wrote:
So we're making pretty heavy use of PyInstanceMethod_New in our python binding library that we've written for a bunch of in house tools. If this isn't the best / correct way to go about adding methods to objects, what should we be using instead?
First of all, the consensus in this thread is not to deprecate instancemethod.
Well, it depends what you mean with "adding methods to objects", that's vaguely formulated. Do you mean adding methods at run-time (a.k.a. monkey-patching) to a pre-existing class? And is the process of adding methods done in C or in Python?
Do you only need PyInstanceMethod_New() or also other PyInstanceMethod_XXX functions/macros?
participants (7)
-
Brett Cannon
-
Christian Heimes
-
Greg Ewing
-
Guido van Rossum
-
Jeroen Demeyer
-
Robert White
-
Serhiy Storchaka