是否可以从 python 中的模块对象生成导入语句?
Is it possible to generate import statement from the module object in python?
在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__
- 它 returns ModuleSpec
具有名称属性
module.__package__
- 不知道为什么但大部分时间都是空的
module.__loader__
——通常是SourceFileLoader
,也有name属性
name 属性的问题是 'posixpath' 对应 os.path
,而 from os import posixpath
显然不起作用。另外,我看不到如何获取父模块(os.path
示例中的 os
)。
是否可以在 Python 中实现可行的(虽然不一定是 production-ready/bulletproof)解决方案?换句话说,是否需要有关包结构的信息来重新创建导入代码preserved/accessible?
可以,而且很简单,但是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
在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__
- 它 returnsModuleSpec
具有名称属性module.__package__
- 不知道为什么但大部分时间都是空的module.__loader__
——通常是SourceFileLoader
,也有name属性
name 属性的问题是 'posixpath' 对应 os.path
,而 from os import posixpath
显然不起作用。另外,我看不到如何获取父模块(os.path
示例中的 os
)。
是否可以在 Python 中实现可行的(虽然不一定是 production-ready/bulletproof)解决方案?换句话说,是否需要有关包结构的信息来重新创建导入代码preserved/accessible?
可以,而且很简单,但是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