加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

如何动态修改函数的本地命名空间?

发布时间:2020-12-20 13:27:55 所属栏目:Python 来源:网络整理
导读:注意:这个问题假定 Python 2.7.3. 我正在寻找一种理智的方法来动态修改函数的本地命名空间,最好是以一种给body函数添加最少杂乱的方式. 我的想法会是这样的: import osfrom namespace_updater import update_localsdef somefunc(x,y,z): # ... # ... # thi
注意:这个问题假定 Python 2.7.3.

我正在寻找一种理智的方法来动态修改函数的本地命名空间,最好是以一种给body函数添加最少杂乱的方式.

我的想法会是这样的:

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...
    # ...
    # ...
    # ...

谢谢!

PS:以下是不起作用的方法.

最天真的方法是这样的:

locals().update(new_locals(locals())

…但是documentation for locals()非常明确地警告不要依赖这样的伏都教来修改局部变量,所以请不要将其作为答案提交(除非您能够在不考虑文档警告的情况下提出一个很好的案例).

接下来在天真的规模就像是

for k,v in new_locals(locals()).items():
    exec ('%s = v' % k)

AFAICT,这样的代码不能“不在路上”(即它必须在函数体内),这是不理想的.但真正的交易破坏者是exec(‘%s = v’%k)黑客攻击会导致一些奇怪的错误.

当我写出“奇怪的错误”时,我的意思是“对于那些对我来说很难掌握的人(‘%s = v’%k)看起来很奇怪的错误”.我对这个黑客的把握有多么脆弱?要回答这个问题,请考虑以下脚本.它有三种变体:(1)完全如图所示; (2)删除第18行的前导号码后; (3)删除第15行和第18行中的第一个#(即对于此变体,没有注释掉代码).我无法预测此脚本的变体(2)和(3)的行为.我甚至无法预测变体(1)的行为超过50%.这是我对exec(‘%s = v’%k)黑客的掌握程度.除非你能够自信而正确地预测这个脚本的三个变体将如何表现(在python 2.7下),可以肯定地说你对这种情况的掌握与我的一样脆弱,你可能应该避开exec(‘ %s = v’%k)也是.

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

解决方法

我将介绍我认为接近合理的唯一方法,然后我会试着说服你不要使用它.

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)

使用这种方法,您至少可以获得代码注入攻击的一些保护.显式指定包含代码“局部变量”的字典,因此您可以完全控制运行exec语句时变量空间的内容.您不必破解函数对象或其他类似物的内部.

我知道decorator module在执行@decorator时使用exec来操作动态创建函数中的参数名称,并且可能还有其他常用模块使用它.但我只有一种情况是,exec明显胜过Python中的替代品,而且还有一种用于评估.

我在你的问题中没有看到这种情况.除非上面的mycode需要做一些非常时髦的事情,比如创建一个以kw给出的参数名称的函数,你很可能只是简单地编写代码,并且可能在紧要关头使用locals().

def process(**kw):
  print 'Value of foo is %s' % (kw['foo'],)
  print 'Value of bar is %s' % (kw['bar'],)

process(foo=2,bar=3)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读