【问题标题】:How do I load and unload a Python module dynamically, disassemble and inspect it, but not execute init code or add it to sys.modules?如何动态加载和卸载 Python 模块、反汇编和检查它,但不执行初始化代码或将其添加到 sys.modules?
【发布时间】:2013-03-05 01:52:55
【问题描述】:

我正在尝试将 Python 模块分解为字节码。

我必须静态或动态导入 Python 模块才能反汇编或检查它吗?如果没有,有什么(pythonic,可移植的)方法?

我想:

  1. 在运行时将可用 Python 模块的二进制数据加载到内存中:
    1. 没有它在sys.modules 中显示为可用模块。
    2. 我不想执行任何模块的__init__ 代码,或者将其添加到任何命名空间。
    3. 加载模块应该没有其他副作用。至于 对于解释器而言,它应该只是要检查的数据块。
  2. 反汇编或以其他方式检查模块的类、函数或数据。
  3. 根据需要卸载模块。

我已经搜索过,我看到了许多动态模块导入的方法(其副作用是执行模块__init__ 代码或其他内联代码,并插入到 sys.modules 中)。但我宁愿不处理这些副作用。

这可能吗?如果是这样,哪些方法最便携/Pythonic?

【问题讨论】:

  • “加载一个模块”而不允许它执行它的 init.py 文件是什么意思?这对我来说似乎很矛盾。
  • 将二进制数据以代码可以访问但不执行的形式加载到内存中。我已更新问题以反映您的反馈

标签: python inspect


【解决方案1】:

我对此进行了一些研究,一种可能的解决方案是使用pyclbr 模块。它的检查查看有关类和函数的基本信息,将其加载到字典中以便于访问。这是一个示例运行:

>>> import pyclbr
>>> import sys
>>> info = pyclbr.readmodule_ex('inspect')
>>> info
{'formatargvalues': <pyclbr.Function object at 0x5083e28e50>, 'walktree': <pyclbr.Function object at 0x5083e28b50>, 'getinnerframes': <pyclbr.Function object at 0x5083e29050>, 'indentsize': <pyclbr.Function object at 0x5083e28710>, 'getmodulename': <pyclbr.Function object at 0x5083e28850>, 'formatannotation': <pyclbr.Function object at 0x5083e28d50>, 'ismemberdescriptor': <pyclbr.Function object at 0x5083e283d0>, 'iscode': <pyclbr.Function object at 0x5083e28550>, 'getsource': <pyclbr.Function object at 0x5083e28b10>, 'formatargspec': <pyclbr.Function object at 0x5083e28dd0>, 'getabsfile': <pyclbr.Function object at 0x5083e288d0>, 'getsourcelines': <pyclbr.Function object at 0x5083e28ad0>, '_getfullargs': <pyclbr.Function object at 0x5083e28c10>, 'isabstract': <pyclbr.Function object at 0x5083e28610>, 'isbuiltin': <pyclbr.Function object at 0x5083e28590>, 'getlineno': <pyclbr.Function object at 0x5083e28f10>, 'getcomments': <pyclbr.Function object at 0x5083e28990>, 'getgeneratorstate': <pyclbr.Function object at 0x5083e293d0>, 'getattr_static': <pyclbr.Function object at 0x5083e29390>, 'getframeinfo': <pyclbr.Function object at 0x5083e28ed0>, 'isgenerator': <pyclbr.Function object at 0x5083e28490>, '_static_getmro': <pyclbr.Function object at 0x5083e29190>, 'isframe': <pyclbr.Function object at 0x5083e28510>, 'getouterframes': <pyclbr.Function object at 0x5083e28f90>, 'getclasstree': <pyclbr.Function object at 0x5083e28b90>, 'getfile': <pyclbr.Function object at 0x5083e287d0>, '_shadowed_dict': <pyclbr.Function object at 0x5083e29310>, 'getargvalues': <pyclbr.Function object at 0x5083e28d10>, 'getmembers': <pyclbr.Function object at 0x5083e28650>, 'BlockFinder': <pyclbr.Class object at 0x5083e28a10>, 'isfunction': <pyclbr.Function object at 0x5083e28390>, 'getargspec': <pyclbr.Function object at 0x5083e28c50>, 'currentframe': <pyclbr.Function object at 0x5083e29090>, 'namedtuple': <pyclbr.Function object at 0x5083e1b150>, 'getmoduleinfo': <pyclbr.Function object at 0x5083e28810>, 'trace': <pyclbr.Function object at 0x5083e29110>, 'isclass': <pyclbr.Function object at 0x5083db8950>, '_is_type': <pyclbr.Function object at 0x5083e29290>, 'getcallargs': <pyclbr.Function object at 0x5083e28e90>, 'ismethoddescriptor': <pyclbr.Function object at 0x5083e28310>, 'isgeneratorfunction': <pyclbr.Function object at 0x5083e28450>, 'isroutine': <pyclbr.Function object at 0x5083e285d0>, 'getfullargspec': <pyclbr.Function object at 0x5083e28cd0>, 'getmro': <pyclbr.Function object at 0x5083e286d0>, 'getargs': <pyclbr.Function object at 0x5083e28bd0>, 'stack': <pyclbr.Function object at 0x5083e290d0>, 'getdoc': <pyclbr.Function object at 0x5083e28750>, 'findsource': <pyclbr.Function object at 0x5083e28950>, 'cleandoc': <pyclbr.Function object at 0x5083e28790>, '_check_class': <pyclbr.Function object at 0x5083e29250>, '_check_instance': <pyclbr.Function object at 0x5083e29210>, 'classify_class_attrs': <pyclbr.Function object at 0x5083e28690>, 'ismodule': <pyclbr.Function object at 0x5083db8910>, 'EndOfBlock': <pyclbr.Class object at 0x5083e289d0>, 'isdatadescriptor': <pyclbr.Function object at 0x5083e28350>, 'getmodule': <pyclbr.Function object at 0x5083e28910>, 'formatannotationrelativeto': <pyclbr.Function object at 0x5083e28d90>, 'getsourcefile': <pyclbr.Function object at 0x5083e28890>, 'ismethod': <pyclbr.Function object at 0x5083e282d0>, 'isgetsetdescriptor': <pyclbr.Function object at 0x5083e28410>, 'istraceback': <pyclbr.Function object at 0x5083e284d0>, 'getblock': <pyclbr.Function object at 0x5083e28a50>}
>>> sys.modules['inspect']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'inspect'

任何更高级的东西,您都必须开始研究通过 ast module 访问抽象语法树。

【讨论】:

  • 这很有帮助,因为我确实需要类浏览器功能,但公开的界面并不能帮助我满足核心要求。我将深入研究 pyclbr 以查看实现是否提供了额外的线索,所以 +1 为您的答案!
  • @Inactivist 你能扩展一下需求吗?你期待什么样的分析?很多更底层的交互由Python Language Services 模块处理。
  • 主要是我想在运行时从模块的方法(和其他属性)中获取字节码数据,但我不想导入模块执行。似乎内置服务假定您想要或已经导入了模块(但我仍在搜索和学习。)我已经更新了我的原始问题以帮助澄清。
【解决方案2】:

我找到了适用于 Python 2.7 的 uncompyle2,其中包含 load a source file and compile it to bytecodesload a module and compile it to bytecodes 的函数,而无需导入模块。

因此,至少它看起来是可行的,但可能涉及在源代码上调用 compile(),或者,如果使用 pyc 文件,可能无法移植(uncompyle2 仅支持 Python 2.7 与 pyc 文件。)

【讨论】:

    猜你喜欢
    • 2017-12-25
    • 1970-01-01
    • 1970-01-01
    • 2013-03-06
    • 1970-01-01
    • 2013-08-06
    • 1970-01-01
    • 2011-04-02
    • 1970-01-01
    相关资源
    最近更新 更多