在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中实现可行的(虽然不一定是生产就绪/防弹的解决方案?换句话说,重新创建导入代码所需的有关包结构的信息是否保留/可访问?
您可以,这很简单,但是os.path
有点奇怪:
def assemble_import(module, name):
return 'import {} as {}'.format(module.__name__, name)
os.path
很奇怪,因为它是ntpath
模块或posixpath
模块的平台相关别名。此功能将使用模块的实际名称,即ntpath
或posixpath
。如果想将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