This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: DOC: inspect.ismethod returns different results on the same basic code between Python2.7 Python3.5
Type: enhancement Stage: resolved
Components: Documentation Versions: Python 3.10
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: andrei.avk, anthony-flury, docs@python, iritkatriel, r.david.murray, steven.daprano
Priority: normal Keywords: easy

Created on 2016-08-30 19:26 by anthony-flury, last changed 2022-04-11 14:58 by admin.

Messages (10)
msg273955 - (view) Author: Anthony Flury (anthony-flury) * Date: 2016-08-30 19:26
Consider the following code in Python2.7 & Python3.5 

    import inspect
    
    class a(object):
         def m(self):
             pass

in Python 2.7 
    
    inspect.ismethod(a.m) returns True

in Python 3.5
 
    inspect.ismethod(a.m) returns False

Not sure which is `correct`, but I can see the Python3.5 result causing some issues with automatic code documenters. 

I have code which will break under Python3.5 with this - my code performs static analysis of code, detecting functions, classes, attributes, and also traversing the mro to find inherited methods etc. Amongst other things this code identifies methods on classes, without instantiating those classes.

This may simply require a documentation change to explain the difference on Py3.5 - rather than a code change.
msg273959 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2016-08-30 19:45
Note that Python 3 did away with unbound methods: in Python 3, `a.m` is simply a function, so there's little the `inspect` module can do to distinguish it from a regular top-level function.

https://docs.python.org/3/whatsnew/3.0.html#operators-and-special-methods
msg273960 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2016-08-30 19:46
They are both correct.  In 2.7 a class method is a method.  In python3, a class method is a function.

As for the docs, the python3 docs say that it returns true for "a bound method on an object", while the python2 docs say "a bound or unbound method".  A class method is not bound, and unbound method do not exist in python3.  So the docs are correct as well.  The notes about the difference could go into a porting guide, but I don't think they belong in the main docs.

To fix your code, just treat function objects on classes as what you are thinking of as methods.  Because they are: any function assigned to a class becomes a bound method when invoked through an instance.  I think that's even backward compatible, though I haven't checked.
msg273967 - (view) Author: Anthony Flury (anthony-flury) * Date: 2016-08-30 21:08
Not sure I agree with closing this. I am not convinced (as a reasonably seasoned developer) that the documentation is clear.

It may not be a bug in the code, resulting as it does from a change in the way methods are implemented in Python 3.5, but I do think that the documentation could be a lot clearer. It does read as if it is written for someone who already knows what the library does, rather than as a guide for someone trying to work through it for the first time.

I have changed this to a documentation issue - I hope that this is ok.
msg273980 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2016-08-31 00:30
> I do think that the documentation could be a lot clearer.

Which specific documentation are you referring to? The "What's New" document from 3.0? That's a historical document, a snapshot of the past.

If you have a concern about the current documentation, can you tell us specifically where and what?
msg273984 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2016-08-31 00:39
The docs do not so much assume you know what the library does, as they assume you know how python3 works.  Which is to say, that bound methods are obtained from instances and that functions defined on a class are functions.  That's documented in the data model docs, and the inspect docs in general assume you understand the python data model and are using inspect to probe it.

As Steven said, if you can point specifically to something you think can be improved we will consider it, but know that the python3 docs are in general written without respect to how python2 worked.  There are very few references to python2 in the python3 docs, and this is by design.  The story is different in the python2 docs, so conceivably there could be something inserted there about the python3 difference.
msg273985 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2016-08-31 00:42
Perhaps we could add a cross link from 'bound method' to the 'instance methods' section of the data model docs.
msg273987 - (view) Author: Anthony Flury (anthony-flury) * Date: 2016-08-31 01:29
Assuming the reader knows the details of how Python works is not a great assumption when those documents are being used (by the most part) by people like me who are reasonable developers but who don't know, and for most cases don't care about the internals of Python.

The inspect library is a bit different I conceed, as the user is starting to poke under the belly of the beast as it were, but i do think it would be useful to link from Inspect to the data model docs, were the terminology is discussed in more detail.

If I had tried to port my existing code to Python3.5, and it would have failed it's test set at this point - I don't think that the inspect library docs as they are would have helped.

I know inspect is deliving into the internals - but for most people a block of code within a def block within a class definition is a method - that is what everyone refers to them - even though internally they aren't bound, and aren't 'methods' strictly speaking - I think the docs should try to bridge the gap between common (non expert) language and the correct language terminology where neccessary
msg388975 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-03-17 22:34
There seems to be agreement on this resolution:

> add a cross link from 'bound method' to
> the 'instance methods' section of the data model docs.

I'm updating version and marking as easy.
msg395275 - (view) Author: Andrei Kulakov (andrei.avk) * (Python triager) Date: 2021-06-07 18:54
The data model docs still have 2 references to unbound methods:

For callables, it may indicate that an instance of the given type (or a subclass) is expected or required as the first positional argument (for example, CPython sets this attribute for unbound methods that are implemented in C).
...
Incorrectly attempting to invoke an unbound method of a class in this way is sometimes referred to as ‘metaclass confusion’, and is avoided by bypassing the instance when looking up special methods:

So the concept of unbound methods is still valid, and in addition I would expect that majority of users think of a method defined in a class as a "method" rather than "function defined in class that will become a method" - perhaps because the former is much shorter ;-)

Therefore inspect.ismethod() returning False can easily cause confusion.

I think it might be worth adding this note to `ismethod` docs, something like:

"While the term 'unbound method' is commonly used for functions defined on class objects, from the point of view of `inspect` it is not a method because the object itself is just a plain function."

I can make a PR if this sounds reasonable?
History
Date User Action Args
2022-04-11 14:58:35adminsetgithub: 72088
2021-08-22 13:09:09mark.dickinsonsetnosy: - mark.dickinson
2021-06-07 18:54:15andrei.avksetnosy: + andrei.avk
messages: + msg395275
2021-03-17 22:34:46iritkatrielsettype: enhancement
title: inspect.ismethod returns different results on the same basic code between Python2.7 Python3.5 -> DOC: inspect.ismethod returns different results on the same basic code between Python2.7 Python3.5

keywords: + easy
nosy: + iritkatriel
versions: + Python 3.10, - Python 3.5
messages: + msg388975
2016-08-31 01:29:31anthony-flurysetmessages: + msg273987
2016-08-31 00:42:41r.david.murraysetmessages: + msg273985
2016-08-31 00:39:32r.david.murraysetmessages: + msg273984
2016-08-31 00:30:41steven.dapranosetnosy: + steven.daprano
messages: + msg273980
2016-08-30 21:08:00anthony-flurysetstatus: closed -> open

assignee: docs@python
components: + Documentation, - Library (Lib)

nosy: + docs@python
messages: + msg273967
resolution: not a bug ->
2016-08-30 19:46:52r.david.murraysetstatus: open -> closed

nosy: + r.david.murray
messages: + msg273960

resolution: not a bug
stage: resolved
2016-08-30 19:45:50mark.dickinsonsetnosy: + mark.dickinson
messages: + msg273959
2016-08-30 19:26:21anthony-flurycreate