Sitelet https://github.com/python/cpython/issues/121027
Skip to content

Add __get__ to the partial object #121027

Description

@serhiy-storchaka

Feature or enhancement

In #119827 (comment), @rhettinger proposed to add the __get__ method to the partial object in functools. This is a breaking change, although the impact may be much lesser than of adding __get__ to builtin functions. But we should follow the common procedure for such changes: first add __get__ that emits FutureWarning with suggestion to wrap partial into staticmethod and return the partial object unchanged, then change the behavior few releases later.

Linked PRs

Activity

  1. ncoghlan commented on Jun 26, 2024

    @ncoghlan
    Contributor

    The "Does practicality beat purity?" question also applies here.

    Yes, if we'd had the placeholder functionality all along we might never have added partialmethod, but given that we did add it, what are we gaining by adding partial.__get__ that justifies the migration cost of having to wrap instances in staticmethod to get the old behaviour back when it was actually desired?

  2. serhiy-storchaka commented on Jun 26, 2024

    @serhiy-storchaka
    MemberAuthor

    I do not know. I have not found any issue which could be solved by adding __get__ to partial. The migration cost could be not high, but the benefit is unclear to me. It may simplify the partialmethod implementation in long run, but I did not check this.

  3. serhiy-storchaka commented on Jun 26, 2024

    @serhiy-storchaka
    MemberAuthor

    For clarification, I do not oppose this feature. But there is a procedure for making breaking changes. It should not bit buried as a side effect of adding other feature.

    This can be worked around with significant core developer support if we decide the benefit of immediate change outweighs the risk. Or if we reclassify it as a bugfix.

  4. rhettinger commented on Jun 26, 2024

    @rhettinger
    Contributor

    what are we gaining by adding partial.get

    We are avoiding a problem that formerly didn't present itself. Partial is almost entirely understood as being an equivalent to a lambda or def. Before `Placeholder' was added, no one would encounter this. Now, it is a certitude.

    Without adding __get__, one user after another will have to discover the hard way that these two are not equivalent:

    set_alive2 = lambda self: self.set_state(True)  
    set_alive3 = partial(set_state, Placeholder, True)
    

    When they learn about the non-equivalence, it will break their mental model of partial() as it did for me.

    Next, they will have to discover a workaround with partialmethod() which is mostly unused, mostly unknown, and really shouldn't be necessary anymore.

    I don't think it should be acceptable to leave partial() in a non-harmonious state just because partialmethod() exists. The mental model of equivalence with lambda and def is too important.

  5. rhettinger commented on Jun 26, 2024

    @rhettinger
    Contributor

    Also, I don't think there is much of a downside. The docs for partial() don't promise to not act like a regular function in a class. It is certainly isn't an advertised feature of partial() that "I am just like an equivalent def or lambda but can't be used as a method."

    There might be some minor disruption but it leads to a better designed more clear outcome than being trapped into a surprising behavior that was never intended.

    If __get__ is not added, I'm thinking of withdrawing my support for Placeholder because it would make this wart prominent and it would limit natural uses of the new feature.

  6. serhiy-storchaka commented on Jun 26, 2024

    @serhiy-storchaka
    MemberAuthor

    As an option, we can add __get__ that emits a FutureWarning in 3.13 and change the behavior in 3.14. This will not delay introducion of Placeholder.

    It may be late for a beta stage, but the premise is that it will not affect much user code. If this is true, adding it in 3.13 is safe. If it is not true, it is still better than breaking that code without a warning.

    Surprisingly, it only breaks few recently added tests in the CPython test suite, and these tests were added specially to test how the code handles such weird corner case. They do not establish the correct behavior, they test that the current behavior will not be changed unintentionally.

    cc @Yhg1s as the RM

  7. rhettinger commented on Jun 26, 2024

    @rhettinger
    Contributor

    +1 for adding a FutureWarning to 3.13 if it is still possible. I expect that people with encounter it rarely and that the workaround is to just wrap partial with staticmethod making the behavior explicit.

    It would also be reasonable to just put a note in the docs. This wasn't a behavior previously promised in the docs and isn't something that people would typically encounter. I've taught partial to thousands of people and only noticed the absence of __get__ when the new Placeholder option became available.

    get the old behaviour back when it was actually desired?
    As near as I can tell, this is almost never desired. And as a code reviewer if someone wanted this behavior, it should be made explicit because almost no one knows about it and it is surprising.

  8. added 3 commits that reference this issue on Jun 27, 2024
  9. added a commit that references this issue on Jun 27, 2024
  10. added a commit that references this issue on Jun 27, 2024
  11. added a commit that references this issue on Jun 27, 2024
  12. 7 remaining items

  13. added 2 commits that reference this issue on Jul 11, 2024
  14. added 2 commits that reference this issue on Jul 17, 2024
  15. added a commit that references this issue on Oct 17, 2025
  16. added a commit that references this issue on Apr 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixestype-featureA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions