How to dynamically modify a function's local namespace?

后端 未结 3 925
走了就别回头了
走了就别回头了 2021-01-13 17:11

NB: This question assumes Python 2.7.3.

I\'m looking for a sane approach to dynamically modify a function\'s local namespace, preferably in a way that adds the lea

相关标签:
3条回答
  • 2021-01-13 17:56

    Not sure if it is possible with an external function only. I've created a snippet:

    def get_module_prefix(mod, localsDict):
        for name, value in localsDict.iteritems():
            if value == mod:
                return name
        raise Exception("Not found")
    
    def get_new_locals(mod, localsDict):
        modulePrefix = get_module_prefix(mod, localsDict)
        stmts = []
        for name in dir(mod):
            if name.startswith('_'):
                continue
            if name not in localsDict:
                continue
            stmts.append("%s = %s.%s" % (name, modulePrefix, name))
        return "\n".join(stmts)
    
    def func(someName):
        from some.dotted.prefix import some.dotted.name
        #here we update locals
        exec(get_new_locals(some.dotted.name, "some.dotted.name", locals()))
        print locals()
        print someName # value taken from aModule instead of parameter value
    
    
    func(5)
    

    where:

    • get_module_prefix is used to find the name under which the module is imported,
    • get_new_locals returns assignment statements which can be used to update locals,

    The actual update of locals is performed in line exec(get_new_locals(some.dotted.name, locals())) where we simply execute assignment statements in which we assign values from the module to local variables.

    I am not sure if it is what you actually ment.

    0 讨论(0)
  • 2021-01-13 18:08

    I'll present the only approach I can think of that is close to reasonable, and then I'll try to convince you not to use it.

    def process(**kw):
      mycode = """\
    print 'Value of foo is %s' % (foo,)
    print 'Value of bar is %s' % (bar,)
    """
      exec mycode in kw
    
    vars = {'foo': 2, 'bar': 3}
    process(**vars)
    

    With this approach, you have at least some protection from code-injection attacks. The dictionary containing the "local variables" of the code is specified explicitly, so you have complete control over what the variable space will be when you run the exec statement. You don't have to hack into the internals of function objects or other such.

    I know that the decorator module uses exec in the implementation of @decorator to manipulate argument names in dynamically created functions, and there may be other common modules that use it. But I have been in only one situation where exec was a clear win over the alternatives in Python, and one for eval.

    I do not see such a situation in your question. Unless mycode from above needs to do something really funky, like create a function with argument names given in kw, chances are you can get away with just writing the code plainly, and maybe using locals() in a pinch.

    def process(**kw):
      print 'Value of foo is %s' % (kw['foo'],)
      print 'Value of bar is %s' % (kw['bar'],)
    
    process(foo=2, bar=3)
    
    0 讨论(0)
  • 2021-01-13 18:11

    May be something like that

    def foo():
        print(x)
    
    foo.__globals__["x"] = "Hello Python"
    
    foo()
    

    unfortunately this does not works in body of function if varible has been defined

    def foo(flag):
        x = "Hello World"
        if flag:
            foo.__globals__["x"] = "Hello Python"
    
        print(x)
    

    prints Hello World in both flag is True or False

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