首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >导入python模块而不实际执行它

导入python模块而不实际执行它
EN

Stack Overflow用户
提问于 2011-12-18 21:53:20
回答 6查看 11.6K关注 0票数 20

在复杂应用程序的上下文中,我需要导入用户提供的“脚本”。理想情况下,脚本应该具有

代码语言:javascript
复制
def init():
    blah

def execute():
    more blah

def cleanup():
    yadda

所以我只是

代码语言:javascript
复制
import imp
fname, path, desc = imp.find_module(userscript)
foo = imp.load_module(userscript, fname, path, desc)
foo.init()

然而,我们都知道,用户的脚本在load_module一运行就是executed。这意味着,脚本可以是这样的:

代码语言:javascript
复制
def init():
    blah

yadda

只要我import脚本,就会调用yadda部件。

我需要的是一种方法:

execute

  • 首先检查它是否有init(),execute()和cleanup()

  • 如果它们存在,一切都很好

  • 如果它们不存在,运行任何其他代码,或者至少在我知道没有init()

之前不运行

通常,我会强制使用相同的旧if __name__ == '__main__'技巧,但我对用户提供的脚本几乎没有控制,所以我正在寻找一种相对容易的解决方案。我见过各种复杂的技巧,包括解析脚本,但没有真正简单的技巧。我很惊讶它竟然不存在..也许我什么都没得到。

谢谢。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2011-12-18 22:51:23

我尝试使用ast模块:

代码语言:javascript
复制
import ast

# which syntax elements are allowed at module level?
whitelist = [
  # docstring
  lambda x: isinstance(x, ast.Expr) \
             and isinstance(x.value, ast.Str),
  # import
  lambda x: isinstance(x, ast.Import),
  # class
  lambda x: isinstance(x, ast.ClassDef),
  # function
  lambda x: isinstance(x, ast.FunctionDef),
]

def validate(source, required_functions):
  tree = ast.parse(source)

  functions = set()
  required_functions = set(required_functions)

  for item in tree.body:
    if isinstance(item, ast.FunctionDef):
      functions.add(item.name)
      continue

    if all(not checker(item) for checker in whitelist):
      return False

  # at least the required functions must be there
  return len(required_functions - functions) == 0


if __name__ == "__main__":
  required_funcs = [ "init", "execute", "cleanup" ]
  with open("/tmp/test.py", "rb") as f:
    print("yay!" if validate(f.read(), required_funcs) else "d'oh!")
票数 10
EN

Stack Overflow用户

发布于 2011-12-20 05:47:04

这里有一个比AST方法更简单(也更幼稚)的替代方法:

代码语言:javascript
复制
import sys
from imp import find_module, new_module, PY_SOURCE


EXPECTED = ("init", "execute", "cleanup")

def import_script(name):
    fileobj, path, description = find_module(name)

    if description[2] != PY_SOURCE:
        raise ImportError("no source file found")

    code = compile(fileobj.read(), path, "exec")

    expected = list(EXPECTED)
    for const in code.co_consts:
        if isinstance(const, type(code)) and const.co_name in expected:
            expected.remove(const.co_name)
    if expected:
        raise ImportError("missing expected function: {}".format(expected))

    module = new_module(name)
    exec(code, module.__dict__)
    sys.modules[name] = module
    return module

请记住,这是一种非常直接的方法,避免了对Python导入机制的扩展。

票数 6
EN

Stack Overflow用户

发布于 2011-12-19 17:19:00

首先,我不需要一些函数,但需要一个使用abc模块或zope.interface的、符合指定接口的类。这会迫使模块的制造者提供您想要的函数。

其次,我不会费心去寻找模块级代码。如果他这样做,这就是模块制造商的问题。这是太多的工作,没有实际的好处。

如果你担心安全问题,无论如何你都需要用沙箱保护代码。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8552165

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档