[Python] Using `setattr` to decorate functions from another module

Discussão em 'Python' iniciado por Stack, Abril 1, 2025.

  1. Stack

    Stack Membro Participativo

    I'm having trouble applying a decorator to an imported function. Suppose I have the following foo.py module:

    # contents of foo.py
    def bar():
    return "hello"


    I now want to import bar from it and apply the lru_cache decorator, so in my main file I do this:

    from functools import lru_cache
    import foo

    def main():
    # caching foo.bar works fine
    for _ in range(2):
    if hasattr(foo.bar, "cache_info"):
    print("bar is already cached")
    else:
    print("caching bar")
    setattr(foo, "bar", lru_cache(foo.bar))

    if __name__ == "__main__":
    main()


    which produces, as expected, the following output:

    caching bar
    bar is already cached


    However, I don't want to import the whole foo module, so now I only import bar and rely on sys.modules to find out where bar comes from. Then main.py becomes:

    from functools import lru_cache
    import sys
    from foo import bar

    def main():
    for _ in range(2):
    if hasattr(bar, "cache_info"):
    print("bar is already cached")
    else:
    print("caching bar")
    setattr(sys.modules[__name__], "bar", lru_cache(bar))


    if __name__ == "__main__":
    main()


    Again, this produces the wanted output:

    caching bar
    bar is already cached


    But now I want my decorating process to be reusable in several modules, so I write it as a function in file deco.py:

    from functools import lru_cache
    import sys

    def mydecorator(somefunction):
    for _ in range(2):
    if hasattr(somefunction, "cache_info"):
    print(f"{somefunction.__name__} is already cached")
    else:
    print(f"caching {somefunction.__name__}")
    setattr(sys.modules[somefunction.__module__], "bar", lru_cache(somefunction))


    And so main.py becomes:

    import sys
    from foo import bar
    from deco import mydecorator

    def main():
    mydecorator(bar)

    if __name__ == "__main__":
    main()


    This time the decoration fails; the output becomes:

    caching bar
    caching bar # <- wrong; should be cached already


    How do I correct my code?

    Continue reading...

Compartilhe esta Página