【问题标题】:Retain environment of helper python script in main script在主脚本中保留辅助 python 脚本的环境
【发布时间】:2018-12-08 16:10:29
【问题描述】:

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

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 和子进程。

【问题讨论】:

  • 只需导入您的 helper 脚本,而不是将其作为子进程调用...
  • 这不是一个优雅的解决方案,但您可以让帮助脚本将变量写入文件(文本、csv、pickle、json),然后从文件中读取主脚本。跨度>
  • @zwer import 不执行脚本,之后我需要调用一些函数来执行该脚本。
  • 我认为您需要将有关问题情况的更多信息放入问题中。因为书面问题听起来像是exec()/execfile() 的工作。
  • 你不能from helper_script import * 吗?

标签: python python-2.7 subprocess


【解决方案1】:

如 cmets 中所述,您应该 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.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()

约亨·里策尔

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】:

    您可以将本地字典传递给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 上的警告:请勿将其用于来自不受信任来源的文件。

    【讨论】:

      【解决方案3】:

      @Daniel Hepper 感谢您的清晰解释。在 Python3.x 的情况下,不支持 execfile。可以参考https://stackoverflow.com/a/437857/1790603

      【讨论】:

        【解决方案4】:

        您可以使用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,然后通过foo.afoo.b 访问ab。 (您可以在代码中的任何位置调用import foo,尽管我认为它只会执行一次)。
        3. 在脚本中显式返回您需要的变量,然后使用execfile 执行它

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-01-22
          • 2018-07-05
          • 1970-01-01
          • 2012-09-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-01-06
          相关资源
          最近更新 更多