如何为Python函数设置环境变量?

1 投票
5 回答
2917 浏览
提问于 2025-04-16 18:25

在Lua中,有一个内置的函数叫做 setfenv(),它可以让你提供一个变量表,作为一个函数的环境。下面是一个使用这个函数的例子:

foo = 1
function f()
    print(blech) --Note that no variable named blech has been defined.
end
variableTable = {blech = foo}
setfenv(f, variableTable)
f() -- This will work and print 1, because blech has been defined as foo's value in the variableTable

我这样做的原因是,这样可以为用户搭建一个平台,让他们能够用Lua编写易于理解的脚本(他们可以写不带参数的函数,并且可以放心地相信变量会存在)。这也提供了一种优雅的方法,来排除我不希望他们使用的模块和函数,以确保安全性(例如,如果你定义的变量表中没有os模块,那么更有经验的用户就无法恶意使用它)。

我希望在Python中也能实现同样的功能。Python中有没有类似的做法呢?

5 个回答

2

你为什么想这么做呢?难道你的代码变得太容易理解了吗?
直接把一个字典或者结构体(struct)传给函数就行了,里面放你的“环境”信息。

编辑:看看你的动机。第一部分我不太明白(在Python里写Lua脚本?这是什么意思?),第二部分明显是错的。这并不能限制环境。首先,你还是可以import os
限制执行是个比较复杂的话题。我知道的一些内容有:

  1. Python的限制模块 - http://docs.python.org/library/restricted.html。这个已经不再推荐使用了。
  2. 一个过时的维基页面 - http://wiki.python.org/moin/SandboxedPython。里面没有什么特别有用的内容。
  3. PyPy。这可能是个不错的选择。PyPy沙箱文档:http://codespeak.net/pypy/dist/pypy/doc/sandbox.html
3

我不太明白你为什么想这么做,不过这里有一种比较“hacky”的方法:

def foo():
    print bar
foo.func_globals['bar'] = 1
foo()

注意:这不是我推荐的做法。

5

这里有个叫做 exec 的东西:

def foo():
    print bar

exec foo.func_code in {"bar": "baz"}

用这个方法其实不是个好主意(我甚至觉得这特别糟糕)。因为它让 foo 的实现变得难以理解,因为你得知道它是怎么被调用的。更好的做法是把参数直接传给函数。

而且,这个方法 并没有 提供任何安全保障。简单来说,Python 本身并不支持限制执行的功能。没有任何东西能阻止用户自己提供这个 foo 的定义:

def foo():
    import os
    os.system("rm -rf /")

就算你没有在映射中提供 os,也不代表他们不能自己去获取它。如果你真的需要限制执行的功能,可能更适合使用 Lua,或者至少可以看看 PyPy 的沙盒模式

撰写回答