Skip to content

Changed behavior of <instancemethod>.__get__ in Python 3.11 #113157

Open

Description

@mschmitzer

Bug report

Bug description:

There is a change in behavior in Python 3.11 that does not seem to be described in the "what's new" document.

In the following code:

class A:
    def meth(self):
      print(self)

class B:
    pass

a = A()
b = B()
b.meth = a.meth.__get__(b, B)
b.meth()

The b.meth() call receives a as the self argument up to Python 3.10, but b in 3.11 and 3.12.

This pattern is used by the Pyramid framework. The change breaks Pyramid applications that use add_request_method(someobject.somemethod, "name").

I have to admit that I do not understand the descriptor protocol (or the documentation of __get__) well enough to say whether this is a legitimate use case, but it does exist in the wild.

CPython versions tested on:

3.9, 3.10, 3.11, 3.12

Operating systems tested on:

Linux

Linked PRs

Activity

  1. Eclips4 commented on Dec 15, 2023

    @Eclips4
    Member
  2. self-assigned this
    on Dec 17, 2023
  3. rhettinger commented on Dec 17, 2023

    @rhettinger
    Contributor

    @MarcSchmitzer is correct and the "return a" behavior should be restored.

    For Python 3.13, this is straightforward. Since classmethod descriptor chaining has now been removed, we can just add back method_descr_get to PyMethod_Type.

    For Python 3.11 and Python 3.12, the situation is more complex and we can't fix any one aspect of the problem without breaking something else. Here are the options that come to mind:

    1. Leave Python 3.11 and 3.12 as-is. But that would be a problem for the Pyramid framework.
    2. Revert a918589 . But that would break @msullivan 's use case.
    3. Apply the 3.13 solution to 3.11 and 3.12. This is the cleanest way in the sense that we will have fully restored the original long-standing behaviors before the classmethod descriptor chaining trainwreck began. However, this path breaks having classmethod wrap property which is something that we know people use — that is why we went through a deprecation period to finally remove it in 3.13.
  4. added a commit that references this issue on Dec 17, 2023
  5. rhettinger commented on Dec 19, 2023

    @rhettinger
    Contributor

    @msullivan Would you be okay with reverting a918589 ? We wouldn't have gone down that path had we known that it would break another part of the API.

  6. rhettinger commented on Dec 21, 2023

    @rhettinger
    Contributor

    For 3.11 and 3.12, I suggest that we revert a918589

    Any objections?

  7. added a commit that references this issue on Dec 21, 2023
  8. erlend-aasland commented on Dec 22, 2023

    @erlend-aasland
    Contributor

    For 3.11 and 3.12, I suggest that we revert a918589

    Any objections?

    cc. @pablogsal as 3.11 RM, and @Yhg1s as 3.12 RM.

  9. added a commit that references this issue on Dec 26, 2023
  10. added a commit that references this issue on Jan 22, 2024
  11. added a commit that references this issue on Feb 11, 2024
  12. added 2 commits that reference this issue on Feb 14, 2024
  13. added a commit that references this issue on Mar 4, 2024
  14. added a commit that references this issue on Apr 17, 2024
  15. added a commit that references this issue on Sep 2, 2024
  16. added a commit that references this issue on Jan 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

type-bugAn unexpected behavior, bug, or error

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions