Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

`__set_name__` hook manually added to `functools.wraps()` descriptor instance never called

I’m trying to add a __set_name__ hook to the descriptor produced by functools.wraps inside a decorator, but it is never called and I don’t see any error messages:

import functools


def wrap(fn):
    """Decorator."""

    @functools.wraps(fn)
    def w(*args, **kwargs):
        return fn(*args, **kwargs)

    # This never gets called.
    def set_name(self, obj, name):
        print(f"inside __set_name__: {self=}, {obj=}, {name=}")

    w.__set_name__ = set_name.__get__(w)
    return w


class Foo:
    @wrap
    def foo(self):
        pass

From what I understand, wrap() is called and its return value bound to the foo variable in the class’s execution frame before the Foo class is created, so the __set_name__ hook should be in place by the time Python looks for it. So why isn’t it being called?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Whenever Python looks for magic methods, it looks on the type of the object, not the instance. What you’ve done is take a function object (the return value of functools.wrap, in this case) and assign something on its __dict__. But for efficiency (and correctness, in some cases), special methods like __set_name__ bypass __dict__ and look on the type object directly. See Special method lookup for details and a rationale.

To make your code work, you need to create a custom callable class (i.e. a class which defines a function called __call__), define __set_name__ on that class, and then make w an instance of that class.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading