Override globals in function imported from another module

前端 未结 3 1339
孤独总比滥情好
孤独总比滥情好 2020-12-21 19:25

Let\'s say I have two modules:

a.py

value = 3
def x()
    return value

b.py

from          


        
相关标签:
3条回答
  • 2020-12-21 19:39

    I had the same problem. But then I remembered eval was a thing.
    Here's a much shorter version(if you don't need arguments):
    b.py:

    from a import x as xx
    
    # Define globals for the function here
    glob = {'value': 4}
    def x():
        return eval(xx.__code__, glob)
    
    

    Hopefully after 2 years it'll still be helpful

    0 讨论(0)
  • 2020-12-21 19:50

    So I found a way to (sort of) do this, although I don't think it entirely solves your problems. Using inspect, you can access the global variables of the file calling your function. So if you set up your files like so:

    a.py

    import inspect
    
    value = 3
    
    def a():
        return inspect.stack()[1][0].f_globals['value']
    

    b.py

    from a import a
    
    value = 5
    
    print(a())
    

    The output is 5, instead of 3. However, if you imported both of these into a third file, it would look for the globals of the third file. Just wanted to share this snippet however.

    0 讨论(0)
  • 2020-12-21 19:55

    I've come up with a solution through a mixture of guess-and-check and research. You can do pretty much exactly what I proposed in the question: copy a function object and replace its __globals__ attribute.

    I am using Python 3, so here is a modified version of the answer to the question linked above, with an added option to override the globals:

    import copy
    import types
    import functools
    
    def copy_func(f, globals=None, module=None):
        """Based on https://stackoverflow.com/a/13503277/2988730 (@unutbu)"""
        if globals is None:
            globals = f.__globals__
        g = types.FunctionType(f.__code__, globals, name=f.__name__,
                               argdefs=f.__defaults__, closure=f.__closure__)
        g = functools.update_wrapper(g, f)
        if module is not None:
            g.__module__ = module
        g.__kwdefaults__ = copy.copy(f.__kwdefaults__)
        return g
    

    b.py

    from a import x
    value = 4
    x = copy_func(x, globals(), __name__)
    

    The __globals__ attribute is read-only, which is why it must be passed to the constructor of FunctionType. The __globals__ reference of an existing function object can not be changed: Why is func.__globals__ documented as read-only?.

    0 讨论(0)
提交回复
热议问题