在主脚本中保留辅助python脚本的环境

时间:2018-06-29 12:48:18

标签: python python-2.7 subprocess

我有一个助手脚本,我想从充当服务器的主脚本中调用它。该主脚本如下所示:

Class Stuff():
    def __init__(self, f):
        self.f = f
        self.log = {}

    def execute(self, filename):
        execfile(filename)

if __name__ == '__main__':
    #start this script as server
    clazz = Stuff()
    #here helper_script name will be provided by client at runtime
    clazz.execute(helper_script)

现在,客户端将通过将其名称提供给主脚本(服务器)来调用此帮助脚本。执行后,我想在主脚本中保留辅助脚本的变量(即:a,b)。我知道一种方法是将这些变量从帮助程序脚本返回到主脚本。但是还有其他方法可以保留帮助程序脚本的所有变量。这是辅助脚本的样子:

import os
a = 3
b = 4

我尝试使用execfile和子进程。

4 个答案:

答案 0 :(得分:7)

您可以将本地字典发送到execfile。执行完文件后,该词典将包含它定义的局部变量。

class Stuff():
    def __init__(self):
        self.log = {}

    def execute(self, filename):
        client_locals = {}
        execfile(filename, globals(), client_locals)
        return client_locals

if __name__ == '__main__':
    #start this script as server
    clazz = Stuff()
    #here helper_script name will be provided by client at runtime
    client_locals = clazz.execute('client.py')
    print client_locals

使用您的client.py,将打印:

{'a': 3, 'b': 4, 'os': <module 'os' from '/Users/.../.pyenv/versions/2.7.6/lib/python2.7/os.pyc'>}

execfile的警告:请勿将其用于不受信任来源的文件。

答案 1 :(得分:0)

如评论中所述,您应该return来自帮助程序脚本的值。如果不止一个,请将其粘贴在列表或字典中(namedtuple很方便)。

关键是您需要将execfile的结果分配给服务器脚本中的变量。不必做任何大的事情,它可以直接转储到列表之类的集合中。

基于返回的代码

主文件

class Stuff():
    def __init__(self, f):
        self.f = f
        self.log = {}
        self.storage = []

    def execute(self, filename):
        self.storage.append(execfile(filename))

if __name__ == '__main__':
    #start this script as server
    clazz = Stuff()
    #here helper_script name will be provided by client at runtime
    clazz.execute(helper_script)

Helper文件(helper.py)

a = 3
b = 4
return (a, b)

替代标准输出

另一种方法是让帮助文件打印结果,但重定向stdout。如果您使用的是subprocess,那么这很简单,documentation中对此进行了详细说明(如果有帮助,我可以添加一个示例)。与exec / execfile相比,我对subprocess方法不太熟悉,但是对this SO question有一个解释。

如果其他SO问题发生任何事情,请复制以下两个示例的代码:

弗雷德里克·哈米迪

    code = """
i = [0,1,2]
for j in i :
print j
"""

from cStringIO import StringIO
old_stdout = sys.stdout
redirected_output = sys.stdout = StringIO()
exec(code)
sys.stdout = old_stdout

print redirected_output.getvalue()

Jochen Ritzel

import sys
import StringIO
import contextlib

@contextlib.contextmanager
def stdoutIO(stdout=None):
    old = sys.stdout
    if stdout is None:
        stdout = StringIO.StringIO()
    sys.stdout = stdout
    yield stdout
    sys.stdout = old

code = """
i = [0,1,2]
for j in i :
    print j
"""
with stdoutIO() as s:
    exec code

print "out:", s.getvalue()

答案 2 :(得分:0)

@Daniel Hepper感谢您的简洁说明。对于Python3.x,不支持execfile。您可以参考https://stackoverflow.com/a/437857/1790603

答案 3 :(得分:0)

您可以使用locals()方法访问在任何给定名称空间中定义的所有符号(变量,类,方法...)。这是一个例子

import os
a = 1
b = 2
return locals()

将产生包含(包括一些技术性内容)的字典

{'os': <module 'os' from '...'>, 'a': 1, 'b': 2}

因此,如果将以上内容保存在名为foo.py的文件中,则可以使用以下值:

foo_vals = execfile(`foo.py`)
print(foo_vals["a"])
> 1

但这不是我要使用的方法。根据您脚本中代码的数量,该词典巨大,并且杂乱了您不需要的内容,而我只会将其用于调试目的。以下是其他选项,按“良好的编码习惯”排序:

  1. 将您的代码放入要导入的类中,然后初始化并按照自己的喜好运行,将所有相关变量保留在该类的名称空间中。
  2. 您可以呼叫import foo,然后使用ab访问foo.afoo.b。 (尽管我认为它只能执行一次,但是您可以在代码内的任何地方调用import foo
  3. 在脚本中明确返回所需的变量,然后使用execfile
  4. 执行