如何导入python中的模块

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何导入python中的模块相关的知识,希望对你有一定的参考价值。

参考技术A 定义模块,只要使用文本编辑器,把一些python代码输入到文本中,然后以.py为后缀名进行保存,任何此类文件都会被认为是python模块。
比如说,下面的代码输入到一个文件中,就可以看作是一个模块:
def
printme(var):
print
varif
__name__
==
'__main__':
printme(1)
假设说输入到a.py中,那么import
a就可以把这个模块导入。
然后可执行a.printme(3),屏幕即可打印出3:
>>>
a.printme(3)3>>>
一个模块顶层定义的变量,会自动变成模块的属性。例如:
data=[1,2,3]def
printme(var):
print
varif
__name__
==
'__main__':
printme(1)
data变量就是模块的一个属性。其实printme也是一个属性,只不过是一个函数罢了。
引入模块示例如下:(假定此时data=[1,2,3]未定义)
>>>
import
a>>>
a.data
Traceback
(most
recent
call
last):
File
"<pyshell#1>",
line
1,
in
<module>
a.dataAttributeError:
'module'
object
has
no
attribute
'data'>>>
reload(a)<module
'a'
from
'C:/py\a.pyc'>>>>
a.data
Traceback
(most
recent
call
last):
File
"<pyshell#3>",
line
1,
in
<module>
a.dataAttributeError:
'module'
object
has
no
attribute
'data'>>>
从上述提示可以看出data属性未定义,此时再在a.py文件中定义data=[1,2,3],重新加载a模块,并输出data属性:
>>>
reload(a)<module
'a'
from
'C:/py\a.py'>>>>
a.data[1,
2,
3]>>>
这里的reload函数可以重新加载一个模块。如果在模块代码中更改了,那么需要重新加载。
上面a.data,就是访问模块中的属性。
上面的例子是导入一个文件作为一个模块。
其实python的模块导入还有更丰富的内容。
除了模块名之外,python也可以导入指定目录路径。python代码的目录就称为包。因此,这类导入就称为包导入。事实上,包导入是把计算机上的目录变成python的一个命名空间。而属性就是目录中包含的子目录或者是模块文件。
看下面例子:
在我的桌面上有一个aa文件夹,里面有bb文件夹,bb里面有a.py这个文件。
那么在aa和bb文件夹中分别放置一个__init__.py,之后,在命令行中import
aa.bb.a,就可以导入模块a了。

如何检查 Python 包中的任何模块是不是从另一个包导入?

【中文标题】如何检查 Python 包中的任何模块是不是从另一个包导入?【英文标题】:How to check if any module in a Python package imports from another package?如何检查 Python 包中的任何模块是否从另一个包导入? 【发布时间】:2022-01-20 16:10:03 【问题描述】:

我想确保一个包 ("pkg-foo") 中的所有模块不会从另一个包 ("pkg-block") 导入。

更新:我知道由于 Python 的活力,有许多黑魔法方法可以导入模块。但是,我只对检查显式导入感兴趣(例如 import pkg.blockfrom pkg.block import ...)。

我想通过pkg-foo 中的单元测试来强制执行此操作,以确保它永远不会从pkg-block 导入。

我怎样才能做到这一点?我使用 Python 3.8+,并希望使用内置插件或 setuptools

目前的半生不熟的解决方案

# pkg_resources is from setuptools
from pkg_resources import Distribution, working_set

# Confirm pgk-block is not in pkg-foo's install_requires
foo_pkg: Distribution = working_set.by_key[f"foo-pkg"]
for req in foo_pkg.requires():
    assert "pkg-block" not in str(req)

然而,仅仅因为pkg-block 没有在setup.pyinstall_requires 中声明,并不意味着它没有在包中导入。所以,这只是一个半生不熟的解决方案。

我的想法是我需要爬取pkg-foo 中的所有模块,并检查每个模块是否从pgk-block 导入。

【问题讨论】:

由于 Python 的灵活性,有很多方法可以导入模块。最后你不能完全确定,只有合理确定。 @MichaelButscher 我已经更新了问题以解决要检查哪些类型的进口,感谢您指出这一点 【参考方案1】:

我认为在您的情况下最简单的方法是模拟不应导入的模块,即pkg-block。为了模拟一个模块,把它放在sys.path 的开头,可能最简单的方法是在项目文件夹中创建一个假模块(或临时替换原始模块),所以它最终会在你的@ 987654323@立即。这会将所有导入“重定向”到您的模拟模块。在模拟模块本身中放置如下内容:

print(f'Module __name__ imported')


def __getattr__(name):
    print(f'Imported attribute name from module __name__')

上面的代码将打印一行通知您导入了模块或其属性,这将适用于直接模块导入和from 导入、函数内部导入、importlib 导入(通过路径导入除外,但我觉得这太深奥了)。为了简化单元测试中对导入的检测,您可能想要引发异常而不是仅仅打印。您也不必进行特定测试来验证没有发生导入,只需运行 pkg-foo 的常规测试套件,看看是否有任何测试由于特定于导入的异常而失败。

示例:

假设文件结构如下:

|---main.py
|
\---pkg
    |---block.py
    |---foo.py
    |---__init__.py

在哪里pkg/block.py

print(f'Module __name__ imported')


def __getattr__(name):
    print(f'Imported attribute name from module __name__')

pkg/foo.py

import importlib

import pkg.block
from . import block
from .block import abc

importlib.import_module('pkg.block')


def from_function():
    from pkg.block import from_function

main.py

import pkg.foo

if __name__ == '__main__':
    pkg.foo.from_function()

那么在执行main.py之后你会得到:

Module pkg.block imported
Imported attribute __path__ from module pkg.block
Imported attribute abc from module pkg.block
Imported attribute abc from module pkg.block
Imported attribute __path__ from module pkg.block
Imported attribute from_function from module pkg.block
Imported attribute from_function from module pkg.block

【讨论】:

【参考方案2】:

所以我的建议是从概念上把这个问题分成两部分。

第一个子问题:确定pkg-foo 中导入的所有模块。让我们使用mod_foo 作为pkg-foo 中的任意导入模块

第二个子问题:确定是否有任何mod_foo 来自pkg-block。如果这些模块都不在pkg-block 中,则通过单元测试,否则,单元测试失败。

要解决第一个子问题,您可以使用 modulefinder.ModuleFinder 类。如the example from the documentation所示,可以为pkg-foo中的每个模块做modulefinder.ModuleFinder.run_script(pathname)。然后,您可以通过从字典modulefinder.ModuleFinder.modules 中获取键来获取模块名称。所有这些模块都将成为您的mod-foo 模块。

要解决第二个子问题,您可以使用mod_foo.__spec__ 如提到的here,mod_foo.__spec__ 将是定义here 的'importlib.machinery.ModuleSpec' 的一个实例。如刚刚链接到的文档中所述,该对象将具有属性name,即:

模块的完全限定名称的字符串。

因此我们需要检查pkg-block 是否在mod_foo.__spec__.name 为每个mod_foo 提供的完全限定名称中。

将所有这些放在一起,类似于以下代码的内容应该可以满足您的需要:

import modulefinder

def verify_no_banned_package(pkg_foo_modules, pkg_ban):
    """
    Package Checker
    :param pkg_foo_modules: list of the pathnames of the modules in pkg-foo
    :param pkg_ban: banned package
    :return: True if banned package not present in imports, False otherwise
    """

    imported_modules = set()

    for mod in pkg_foo_modules:
        mod_finder = modulefinder.ModuleFinder()
        mod_finder.run_script(mod)
        mod_foo_import_mods = mod_finder.modules.keys()
        imported_modules.update(mod_foo_import_mods)

    for mod_foo in imported_modules:
        mod_foo_parent_full_name = mod_foo.__spec__.name
        if pkg_ban in mod_foo_parent_full_name.split(sep="."):
            return False
    return True

【讨论】:

这可能会起作用,除非我的 pkg-foo 使用命名空间包,而 ModuleFinder 在 2021 年 12 月 27 日使用 Python 3.8.12 时不适用于 bugs.python.org/issue40350 命名空间包( 流泪)。另一个注意事项是,我将这个答案的pkg_foo_modulespkg_foo_modules 参数传递给了绝对模块路径列表(例如["/abs/path/to/file.py", ...])。我能够使用 setuptools.find_packagespkgutil.iter_modules per this answer 来实现这一点。

以上是关于如何导入python中的模块的主要内容,如果未能解决你的问题,请参考以下文章

如何从python中的其他目录导入模块? [复制]

python中pil如何导入?

如何从python中的测试模块导入src

如何将一个函数中的列表导入另一个 python 模块?

如何从 Python 中的子文件夹导入模块或文件?

对如何从模块中的其他目录/父目录导入感到困惑(python 3)