我正在尝试使用importlib库来验证在Python 3.5.2中执行脚本的计算机上是否安装了nmap库
我正在尝试使用importlib.util.find_spec("nmap")但收到以下错误.
>>> import importlib
>>> importlib.util.find_spec("nmap")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'importlib' has no attribute 'util'
Run Code Online (Sandbox Code Playgroud)
谁能告诉我哪里出错了?
编辑
我能够使用以下代码使函数工作.
#!/usr/bin/pythonw
import importlib
from importlib import util
#check to see if nmap module is installed
find_nmap = util.find_spec("nmap")
if find_nmap is None:
print("Error")
Run Code Online (Sandbox Code Playgroud) 使用不推荐使用的模块imp,我可以编写一个自定义导入钩子,在Python导入/执行之前动态修改模块的源代码.给定源代码作为source下面命名的字符串,创建模块所需的基本代码如下:
module = imp.new_module(name)
sys.modules[name] = module
exec(source, module.__dict__)
Run Code Online (Sandbox Code Playgroud)
由于imp被弃用,我想做类似的事情importlib.[编辑:还有其他imp方法需要替换来构建自定义导入钩子 - 所以我要找的答案不仅仅是替换上面的代码.]
但是,我还没弄清楚如何做到这一点.将导入库文件有一个功能,从"规范"创建模块,其中,据我所知,是包括自己的装填重新定义它们,以便能够从字符串创建模块没有明显的方式对象.
我创建了一个最小的例子来证明这一点; 有关详细信息,请参阅自述文件.
我有MyEnum一个源自 的枚举enum,在文件中定义,myenum.py例如:
# myenum.py
import enum
class MyEnum(enum.Enum):
ONE = 1
TWO = 2
Run Code Online (Sandbox Code Playgroud)
然后,我使用该importlib.import_module()方法导入该文件。我创建了a一个枚举实例,并测试它的值:它是正确的,正如预期的那样。
但是,如果我重新加载文件,则使用importlib.reload(),a不再等于MyEnum.ONE。是什么原因造成的?我使用的是Python 3.7。
# test.py
import importlib
def test_enum(e):
print(e, myenum.MyEnum.ONE)
print("test is :", e==myenum.MyEnum.ONE)
if __name__=='__main__':
globals()["myenum"] = importlib.import_module("myenum")
a = myenum.MyEnum.ONE
test_enum(a)
importlib.reload(globals()["myenum"])
test_enum(a)
Run Code Online (Sandbox Code Playgroud)
结果
MyEnum.ONE MyEnum.ONE
test is : True
MyEnum.ONE MyEnum.ONE
test is : False
Run Code Online (Sandbox Code Playgroud)
编辑:经过进一步研究,Python 中的枚举似乎是按 ID 进行比较的。但是,当重新导入模块时,我的枚举的 ID 发生了更改,这就是比较返回 的原因False。
有哪些选项可以避免此 ID …
假设我有一个这样的模块文件:
# my_module.py
print("hello")
Run Code Online (Sandbox Code Playgroud)
然后我有一个简单的脚本:
# my_script.py
import my_module
Run Code Online (Sandbox Code Playgroud)
这将打印"hello".
假设我想"覆盖"该print()函数,以便它返回"world".我怎么能以编程方式执行此操作(无需手动修改my_module.py)?
我想的是我需要以某种方式修改my_module导入之前或导入时的源代码.显然,我导入后无法执行此操作,因此使用解决方案unittest.mock是不可能的.
我还以为我可以读取文件my_module.py,执行修改,然后加载它.但这很难看,因为如果模块位于其他地方,它将无法工作.
我认为,好的解决方案就是利用importlib.
我阅读了文档,发现了一种非常相互交叉的方法:get_source(fullname).我以为我可以覆盖它:
def get_source(fullname):
source = super().get_source(fullname)
source = source.replace("hello", "world")
return source
Run Code Online (Sandbox Code Playgroud)
不幸的是,我对所有这些抽象类有点迷失,我不知道如何正确执行此操作.
我徒劳地试过:
spec = importlib.util.find_spec("my_module")
spec.loader.get_source = mocked_get_source
module = importlib.util.module_from_spec(spec)
Run Code Online (Sandbox Code Playgroud)
欢迎任何帮助.
在我的模块中,我有几个依赖于具有较长启动时间的外部模块的功能.我该怎么用LazyLoader?如果我有
import veggies
Run Code Online (Sandbox Code Playgroud)
要么
import veggies.brussels.sprouts
Run Code Online (Sandbox Code Playgroud)
要么
from veggies.brussels import sprouts
Run Code Online (Sandbox Code Playgroud)
如何替换这些语句以便LazyLoader模块内容的执行被推迟到需要时?
从文档中可以立即明白如何使用它.没有示例,并且nullege代码搜索仅提供Python本身包含的单元测试.
不要感到困惑,有大量关于安装 Python 包、如何导入生成的模块以及列出可用包的问题。但是,如果您没有pip--what-provides样式文件或Pipenv Pipfile ,则似乎没有与 pip 等效的选项。此问题与上一个问题类似,但要求提供父包,而不是其他元数据。也就是说,这些其他问题没有得到很多关注或得到许多接受的答案 - 例如。如何查找给定模块的 python 包元数据信息。就这样砥砺前行……requirements.txt
举例来说,有两个包(仅举几例)将安装名为的模块serial- 即pyserial和serial。因此,假设安装了其中一个软件包,我们可以使用 pip list 找到它:
python3 -m pip list | grep serial
Run Code Online (Sandbox Code Playgroud)
但是,如果包的名称与模块的名称不匹配,或者您只是想找出要安装的包(在旧服务器或开发计算机上工作),就会出现问题。
您可以检查导入模块的路径 - 这可以给您提供线索。但继续这个例子......
>>> import serial
>>> print(serial.__file__)
/usr/lib/python3.6/site-packages/serial/__init__.py
Run Code Online (Sandbox Code Playgroud)
它位于一个serial目录中,但实际上只安装了pyserial ,而不是serial:
>>> import serial
>>> print(serial.__file__)
/usr/lib/python3.6/site-packages/serial/__init__.py
Run Code Online (Sandbox Code Playgroud)
我能想到的最接近的是生成一个可能在依赖子文件上失败的requirements.txtvia (就像我所做的那样),或者通过Pipenvpipreqs ./反向检查依赖关系(这会带来一整套新问题来完成所有设置):
> python3 -m pip list | grep serial
pyserial …Run Code Online (Sandbox Code Playgroud) PyCharm告诉我imp已被弃用,所以我想知道是否有任何类似的imp.new_module for importlib.
我的问题类似于如何在给定完整路径的情况下导入模块?但是,我没有导入.py源文件,而是导入了带有.pyd的程序包。
在运行时,我根据一些动态生成的c代码创建新的软件包模块。我成功生成了包含__init__.py文件和F的软件包Foo mod.pyd:
/a/temp/dir/foo/
__init__.py
bar.pyd
Run Code Online (Sandbox Code Playgroud)
我正在使用的示例代码是
import importlib.util
spec = importlib.util.spec_from_file_location("foo.bar", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
foo.bar()
Run Code Online (Sandbox Code Playgroud)
如果我尝试从pyd 使用spec_from_file_location('foo.bar', '/a/temp/dir/foo/__init__.py')模块bar,则无法加载。
如果我尝试使用,spec_from_file_location('foo.bar', '/a/temp/dir/foo/')则spec_from_file_location返回None。
如果尝试使用spec_from_file_location('foo.bar', '/a/temp/dir/foo/bar.pyd'),则会出现以下错误堆栈:
File "<frozen importlib._bootstrap>", line 577, in module_from_spec
File "<frozen importlib._bootstrap_external>", line 903, in create_module
File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
ImportError: DLL load failed: A dynamic link library (DLL) initialization routine failed.
Run Code Online (Sandbox Code Playgroud)
推荐的4行importlib解决方案的替代方法是为MetaPathFinder和创建具体的类SourceLoader。我的以下 …
我正在维护一个 python 包,其中我做了一些重组。现在,我想支持仍然这样做的客户,from my_package.old_subpackage.foo import Foo而不是新的from my_package.new_subpackage.foo import Foo,而不明确重新引入许多进行转发的文件。(old_subpackage仍然存在,但不再包含foo.py。)
我了解到有“加载器”和“查找器”,我的印象是我应该为我的目的实现一个加载器,但到目前为止我只实现了一个查找器:
RENAMED_PACKAGES = {
'my_package.old_subpackage.foo': 'my_package.new_subpackage.foo',
}
# TODO: ideally, we would not just implement a "finder", but also a "loader"
# (using the importlib.util.module_for_loader decorator); this would enable us
# to get module contents that also pass identity checks
class RenamedFinder:
@classmethod
def find_spec(cls, fullname, path, target=None):
renamed = RENAMED_PACKAGES.get(fullname)
if renamed is not None:
sys.stderr.write(
f'WARNING: {fullname} was …Run Code Online (Sandbox Code Playgroud) 我有一个模块和一个模块加载器。该模块使用 numba。
当我使用 动态加载模块后调用模块的函数时importlib,我遇到了几个错误。当我执行static导入并调用该函数时,一切正常。
当我不使用 numba 时,静态和动态导入都可以正常工作。
这是一个重现问题的简单示例:
模块mymod.py:
from numba import jit
@jit(nopython=True)
def process():
a = 5
res = a + 5
return res
Run Code Online (Sandbox Code Playgroud)
有效的模块加载器:(runb.py静态导入)
import mymod
def main():
res = mymod.process()
print(res)
if __name__=="__main__":
main()
Run Code Online (Sandbox Code Playgroud)
不工作的模块加载器:(run.py动态导入)
from pathlib import Path
import importlib.util
def main():
module_path = "./mymod.py"
spec = importlib.util.spec_from_file_location(Path(module_path).name, module_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
res = module.process()
print(res)
if __name__=="__main__":
main()
Run Code Online (Sandbox Code Playgroud)
软件上下文:
python ×10
python-importlib ×10
python-3.x ×4
import ×1
import-hooks ×1
mocking ×1
numba ×1
pip ×1
python-3.5 ×1