Using python decorator functions from a different module

16,640

Solution 1

This is a bit hacky, but try this in othermodule.py:

import sys
def decorator(cls):
    mod = __import__(cls.__module__)
    mod.root = cls

Solution 2

That already works:

from othermodule import decorator

@decorator
class Someclass:
    pass

Just put in othermodule.py:

def decorator(cls):
    #.... do something with cls
    return cls

Solution 3

Having a decorator modify the global namespace if any module, let alone another module, is bad and never necessary. Code that mutates far-away globals is difficult to read and maintain. You should definitely consider modifying your design to avoid mutable global state and especially implicit assignment.

Share:
16,640
Doug W
Author by

Doug W

Updated on June 03, 2022

Comments

  • Doug W
    Doug W about 2 years

    I want to use a function from another module as a decorator, but I need it to manipulate the current module's global namespace.

    For example, I want to be able to go from this:

    class SomeClass:
        pass
    
    root = SomeClass
    

    to this:

    from othermodule import decorator
    
    @decorator
    class Someclass:
        pass
    

    Any ideas?

  • Doug W
    Doug W about 14 years
    Yeah I know it works in general, but it's the fact that I want a decorator from the imported module to define a variable in the original module's global scope that causes trouble.
  • Doug W
    Doug W about 14 years
    Yeah that worked, thanks. Actually I ended up using mod = sys.modules[cls.__module__] because the import call only returned the top level module (cls.__module__) was 4 levels deep - ie mod1.mod2.mod3.mod4
  • Marius Gedminas
    Marius Gedminas about 14 years
    Incidentally, mod = __import__(cls.__module__, {}, {}, ('*', )) would return the mod4 module, not the outermost mod1 package
  • Mike Graham
    Mike Graham about 14 years
    This is a direct answer (although error-prone for packages and such), but very scary code. Also, it's sort of silly to use setattr with string literals. setattr(foo, 'bar', baz) is spelled foo.bar = baz.
  • Duncan
    Duncan about 14 years
    Yes, the setattr was excessive. I've removed it. The code isn't all that scary: module is a documented attribute of classes. Whether the OP should actually be doing it at all is of course another question.