是否可以从python中的模块对象生成import语句?

问题描述 投票:1回答:1

在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'

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

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

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

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

python python-3.x python-import code-generation
1个回答
1
投票

您可以,这很简单,但是os.path有点奇怪:

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

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

对于actual包子模块,例如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
© www.soinside.com 2019 - 2024. All rights reserved.