【问题标题】:Is it possible to generate import statement from the module object in python?是否可以从 python 中的模块对象生成导入语句?
【发布时间】:2020-07-17 20:42:31
【问题描述】:

在 Python 中,使用isinstance(obj, types.ModuleType) 很容易检查对象是否为模块。我们还可以以编程方式生成模块。然而,我有兴趣反过来 - 生成将创建导入导致模块被添加到 globals/locals 命名空间的代码。基本上是这样的函数assemble_import

def assemble_import(module: types.ModuleType, name: str) -> str:
    pass

大致满足以下条件:

import statistics
assert assemble_import(statistics, 'statistics') = 'import statistics'

from os import path
assert assemble_import(path, 'path') = 'from os import path'

import collections.abc
abc = collections.abc
assert assemble_import(abc, 'abc') = 'from collections import abc'

import abc as xyz
assert assemble_import(xyz, 'xyz') = 'import abc as xyz'

希望它使用抽象语法树,而是使用模块对象本身。到目前为止我所尝试的:

  • module.__spec__ - 它返回带有 name 属性的 ModuleSpec
  • module.__package__ - 不知道为什么,但大部分时间都是空的
  • module.__loader__ - 通常是SourceFileLoader,也有name属性

name 属性的问题在于它是os.path 的“posixpath”,而from os import posixpath 显然不起作用。另外,我没有看到如何获取父模块(os.path 示例中的os)。

是否可以在 Python 中实现可行的(尽管不一定是生产就绪/防弹的)解决方案?换句话说,重新创建导入代码所需的包结构信息是否保留/可访问?

【问题讨论】:

  • 听起来像是 XY 问题。你试图通过这种方式实现的实际目标是什么?你知道docs.python.org/3/library/importlib.html吗?
  • 谢谢。是的,我知道。我不想操作我的自定义模块,但是任何用户提供的模块,我很好奇是否可以使用 Python 实现从对象生成代码。
  • 我还不明白:在assert assemble_import(xyz, 'xyz') = 'import abc as xyz' 中,abc 应该从哪里输出?
  • 来自模块对象。 xyz 别名为 abc (import abc as xyz)。
  • os.path 在模块通常不应该有的方式上是独一无二的和特殊的——如果它不是 Python 的早期部分,它可能不会这样设计。如果您真的想将其视为os.path 而不是posixpathntpath,则最好的选择是特殊情况。

标签: python python-3.x python-import code-generation


【解决方案1】:

可以,而且很简单,但是os.path 会有点奇怪:

def assemble_import(module, name):
    return 'import {} as {}'.format(module.__name__, name)

os.path 很奇怪,因为它是ntpath 模块或posixpath 模块的平台相关别名。此函数将使用模块的实际名称,ntpathposixpath。如果您想将os.path 视为os.path,则可以对其进行特殊处理,尽管它可能不是最佳设计选择。

对于实际包子模块,如collections.abc,此函数会将它们视为其包含包的子模块:

>>> assemble_import(collections.abc, 'abc')
'import collections.abc as abc'

但是对于os.path,这会给你类似的输出

>>> assemble_import(os.path, 'path')
'import posixpath as path'

如果您希望导入看起来更像人类通常编写的内容,您可以在函数中添加一些逻辑:

def assemble_import(module, name):
    pname, _, mname = module.__name__.rpartition('.')
    if pname:
       statement = 'from {} import {}'.format(pname, mname)
    else:
       statement = 'import ' + mname
    if mname != name:
       statement += ' as ' + name
    return statement

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多