JustOnePixel
JustOnePixel

Reputation: 699

How can I set the function environment for a Python function?

In Lua, there's a built-in function called setfenv(), which allows you to supply a table of variables as an environment for a function. Here's an example that uses it:

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

My motivation for doing this is that it allows me to set up a platform so that users can write easy-to-understand scripts in Lua (they can write nullary functions and can simply trust that variables will be there for them). It also provides an elegant method of excluding modules and functions that I don't want them to use for security reason (e.g. if you define a variable table that doesn't have the os module defined, there's no way a more knowledgeable user could use it maliciously).

I would like to be able to achieve the same thing in Python. Is there something similar that can be done in Python?

Upvotes: 1

Views: 3163

Answers (5)

thule
thule

Reputation: 4222

Why would you ever want to do that? Did your code become too readable?
Just pass a dict or a struct with your 'env' to the function.

EDIT: read your motivation. First part i cannot understand (writing lua scripts in python? what does that mean?), the second is plain wrong. This is no way to restrict enviroment. For one, you can still import os.
Restricted execution is kinda a complex topic. Some stuff i know of:

  1. Python restricted module - http://docs.python.org/library/restricted.html. Deprecated.
  2. An outdated wiki page - http://wiki.python.org/moin/SandboxedPython. Nothing insanely useful there.
  3. PyPy. This is probably the way to go. PyPy sandbox docs: http://codespeak.net/pypy/dist/pypy/doc/sandbox.html

Upvotes: 2

Jean-Paul Calderone
Jean-Paul Calderone

Reputation: 48335

There's exec:

def foo():
    print bar

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

This isn't particularly good style (I would even say that it is particularly bad). It makes the implementation of foo difficult to understand since it relies on knowing about the special way in which it will be called. Instead, pass arguments to functions.

This does not provide any measure of security. As a first approximation, Python does not include any restricted execution capabilities. Nothing stops a user from supplying this definition of foo instead:

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

Just because you didn't supply os in the mapping doesn't mean they can't go get it themselves. If you really need restricted execution, then you might want to stick with Lua, or at least investigate PyPy sandboxed mode.

Upvotes: 5

Platinum Azure
Platinum Azure

Reputation: 46193

You can have your function take an extra value that is a blob of keyword arguments:

def printKeyValuePairs(preface, **kwargs):
    print preface + "\n"

    for k,v in kwargs.iteritems():
        print k + ": " + v + "\n"

# usage
printKeyValuePairs("Here are my key-value pairs:", One=1, Two=2, Three=3)
# prints:
# Here are my key-value pairs:
# One: 1
# Two: 2
# Three: 3
# (note that the above lines could be ordered any which way... might want to
# sort first if it matters)

Upvotes: 0

samplebias
samplebias

Reputation: 37909

I'm not sure why you'd want to do this, but here is one hacky way:

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

Caveat: This is not something I recommend doing.

Upvotes: 3

Daenyth
Daenyth

Reputation: 37441

I don't know of any sane way to do that. Just use function arguments.

def f(blech):
    print(blech)

If you want it to have many variables, stick them in a dict and pass that.

def f(vars):
    print(vars['blech'])
    print(vars['fizz'])

Upvotes: 0

Related Questions