How to dynamically modify a function's local namespace?
我正在寻找一种明智的方法来动态地修改函数的本地名称空间,最好是以一种对主体函数增加最少混乱的方式。
我的想法是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import os from namespace_updater import update_locals def somefunc(x, y, z): # ... # ... # this and that # ... # ... if os.environ.get('FROBNICATE'): from frobnitz import frobnicate update_locals(frobnicate(locals())) # # life goes on, possibly with duly frobnicated local variables... # ... # ... # ... |
谢谢!
附:下面是一些不起作用的方法。
最天真的做法是:
1 | locals().update(new_locals(locals()) |
号
…但是
下一个天真的尺度是
1 2 | for k, v in new_locals(locals()).items(): exec ('%s = v' % k) |
事实上,这样的代码不能"偏离方向"(也就是说,它必须在函数的主体中),这是不理想的。但真正的破坏者是
当我写"奇怪的虫子"的时候,我的意思是"那些对我这样的江户人来说看起来很奇怪的虫子"。我对这个黑客的掌握有多脆弱?要回答这个问题,请考虑下面的脚本。它有三种变体:(1)完全如图所示;(2)删除第18行的前导
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | x = 'global x' # 01 y = 'global y' # 02 def main(): # 03 x = 'local x' # 04 y = 'local y' # 05 run(locals()) # 06 print 'OK' # 07 return 0 # 08 # 09 def run(namespace): # 10 global y # 11 print locals().keys() # 12 for k, v in namespace.items(): # 13 print '%s <- %r' % (k, v) # 14 exec ('%s = v' % k) #in locals() # 15 print locals().keys() # 16 x = x # 17 #z = lambda: k # 18 print x # 19 print y # 20 # 21 exit(main()) # 22 |
。
我将介绍我能想到的唯一接近合理的方法,然后我将试图说服你不要使用它。
1 2 3 4 5 6 7 8 9 | 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) |
。
使用这种方法,至少可以防止代码注入攻击。包含代码的"局部变量"的字典是明确指定的,因此在运行
我知道decorator模块在
我在你的问题上看不到这样的情况。除非上面的
1 2 3 4 5 | def process(**kw): print 'Value of foo is %s' % (kw['foo'],) print 'Value of bar is %s' % (kw['bar'],) process(foo=2, bar=3) |
不确定是否可以只使用外部功能。我创建了一个片段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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" ".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) |
哪里:
get_module_prefix 用于查找导入模块的名称,get_new_locals 返回可用于更新局部变量的赋值语句,
局部变量的实际更新是在
我不确定这是否是你真正想要的。
可能是那样的
1 2 3 4 5 6 | def foo(): print(x) foo.__globals__["x"] ="Hello Python" foo() |
不幸的是,如果变量已定义,则在函数体中不起作用。
1 2 3 4 5 6 | def foo(flag): x ="Hello World" if flag: foo.__globals__["x"] ="Hello Python" print(x) |
号
在两个标志中打印Hello World是真是假