模块pdf2image.dll加载失败_【Python技术进阶2】Python的模块和包的详细指南

刚开始入门时,代码都是几行,十几行,在Python自带的解释器中就可以完成。逐渐的,代码会到几十行、上百行,就会用PyCharm/VSCode之类的Python IDE,通常是新建一个py文件,代码都写在这个py文件。

小伙伴们学习都很努力,经过一段时间Python基础知识的学习,已经迫不及待的想要一展身手。有一位小伙伴叫小帅,要完成这样的功能:“从一批存储不同业务数据的Excel文件中读取数据,然后对读取到的数据进行简单的转换处理,最后再写入到数据库。”需求挺简单的,小伙伴就开始写代码,写着写着,发现好几个函数好长呀,都是好几百行的代码,整个py文件有1千多行的代码。代码终于写完了,开始要用真实数据进行调试,这时候发现调试很不熟手。“感觉好乱呀,一会儿要用鼠标拖动滚动条到文件最上面位置,查看读取Excel数据的代码逻辑,一会儿又要拖动到文件中间位置查看数据转换后的格式为什么不对。

小帅就来问飞哥,“一个文件里面的代码太多了,函数也很长,看代码以及调试代码的效率好低,应该怎么优化?”

飞哥说,“你这问题,很多Python新手小伙伴都会遇到,包括飞哥自己以前也是这么干的。要解决这问题也很简单,学习了今天介绍的模块和包的Python知识后,你就知道怎么做了。

接下来,飞哥就给小伙伴详细聊聊Python的模块和包,它是一个很重要的知识点,能够帮助小伙伴有效的提升模块化编程思维,提高代码的可复用性。

01 模块

在Python中,一个.py文件就是一个模块,模块名就是.py文件的文件名称。通过导入模块的方式,模块里面的函数以及变量等对象就可以被其它py文件使用。

正是由于模块可导入的特性,可以把一个几千行的Py文件,通过重构的方式,将不同功能的代码分离,分别放在不同的Py文件里,就可以把一个大文件分割成几个小的只有几百行的Py文件。这样,保持了每个模块文件的代码功能的单一性,从而提高代码的可维护性以及可复用性。通过不同功能模块的组合,就可以完成一个功能复杂的需求,这就像乐高积木一样。

现在我们就来现学现用,上面小帅同学的问题,就有了优化方案:

1) 将文件中的代码功能进行剥离,分成Excel读取功能、数据处理功能、数据入库功能,分别放入下图右边所示的3个模块文件中。

2)在主文件中,分别导入上述3个模块文件,调用相关模块的接口函数,完成整个需求的功能。

3bf8381ae79ce2911b0974017a2e20ee.png

02 模块的使用

模块是一个功能独立的代码文件,要使用模块,必须先导入模块。每个模块被导入后,都会创建一个它自己的唯一的名称空间,通常模块名就代表了这个名称空间。因此,访问模块的变量、函数等属性时,必须使用模块名+点号+标识符的方式,基本语法如下所示:

模块名 .标识符

1、导入模块的方法

首先,飞哥先定义一个很简单的测试模块,然后分别说明以下各种不同的导入模块的方法。

自定义模块hello.py的代码如下:

#!/usr/bin/python3# -*- coding: utf-8 -*-name = "hello.py"print("各位请注意,我来啦")def test1():    print("哈喽, 我是测试1")    def test2():    print("哈喽, 我是测试2")

1)import 模块名

示例1,导入内置模块

>>> import math  # 导入math模块>>> math.pow(2,3) # 调用math模块的pow函数8.0>>> 

示例2,导入自定义模块

在main.py中使用时,按如下方式调用自定义模块:

# 导入模块import hello# 调用模块中的变量print(hello.name)# 调用模块中的函数hello.test1()hello.test2()

示例3,可以一次导入多个模块,但代码规范中不提倡这种方式,应该使用一行导入一个模块的方式:

# 不推荐的一行导入多个模块>>> import os, sys, math>>> # 推荐的是一行导入一个模块import mathimport osimport sys

2)import 模块名 as 别名

有时候,一个模块的名称很长,在使用的时候就很不方便,这时候就可以给它起一个别名(起一个简短的名称),简化模块名称。其实,有时候模块名称也不长,但为了书写方便或是惯例,导入模块的时候也会起一个很短的别名。

# 使用别名导入模块import numpy as np# 通过别名引用模块中的属性img = cv2.imread("./cat.jpg")emptyImage = np.zeros(img.shape, np.uint8)

另外一种情况,避免命名冲突。比如,在当前文件中有一个标识符(函数或是变量或是第三方模块)与我们自定义的模块名重复了,可以在导入模块时给它起一个别名,来解决名称冲突。

例如,在main.py中,定义一个hello函数,就会出现冲突:

import hellodef hello():    print("哈喽,main文件")# 这时候出现名称冲突,这个全局的hello函数的名称# 会覆盖hello模块的名称,导致下面的模块调用失败hello.test1()

上面的代码执行后,会出现下面的异常:

4be37e04e6d7c2dea58928d3462e19a4.png

上面这种情况,其实模块已经导入,只是模块名称hello和模块本身失去了联系(失联状态),就如同擦肩而过的2个人,那个TA其实一直都在,只是你无法看到而已。

通过别名的方式,就可以解决上面的问题:

import hello as hidef hello():    print("哈喽,main文件")# 通过别名解决命名冲突hi.test1()
3) from 模块名 import 标识符

很多时候,我们为了完成一个功能,要使用另一个模块中的2个函数而已,而且功能也比较简单。就可以直接导入模块中的属性,在使用的时候,就如同本地定义的变量一样直接使用,不需要以模块名+点号的方式来访问。注意,这种方式,由于没有命名空间的限制,属性被导入到当前上下文的命名空间里,可能出现名称覆盖或命名冲突的情况。

# 可以一次导入1个也可以导入多个# 导入多个属性时,属性之间用逗号分隔from hello import test1, test2# 直接访问模块中的属性test1()test2()

4)from 模块名 import *

将模块中所有可导出的属性都导入到当前上下文的命名空间。在使用的时候,就如同本地定义的变量一样直接使用,不需要以模块名+点号的方式来访问。但是,由于被导入的属性很多,尤其是使用第三方模块时,你自己可能都不知道有哪些属性,因此,非常容易出现名称覆盖或命名冲突的情况。在代码规范中严禁使用这种导入方式。平时,在一些临时性的测试中,可以偶尔使用。

from hello import * # 直接访问模块中的属性test1()test2()

5)from 模块名 import 标识符 as 别名

它的作用与2)中的作用类似。一是解决命名冲突或覆盖,二是简化属性的名称或是简化包中子模块的名称。

示例1,导入模块的属性名称时使用别名:

from hello import test1 as hi1, test2 as hi2# 直接访问属性的别名hi1()hi2()

示例2,导入包的子模块时使用别名:

import numpy as npimport cv2 as cvfrom matplotlib import pyplot as plt  #简化包中子模块的导入名称img = cv.imread('die.png')# 通过模块别名访问函数plt.imshow(img)

2、导入和加载

一个模块可以被导入(import)多次,但只会被加载一次。当模块被加载时,被导入模块的顶层代码将直接被执行,比如模块中定义的全局变量、类和函数的定义、全局的函数调用等等。

示例1,测试模块hello.py代码如下:

#!/usr/bin/python3# -*- coding: utf-8 -*-name = "hello.py"print("__name__的值:", __name__)print("各位请注意,我来啦")def test1():    print("哈喽, 我是测试1")    def test2():    print("哈喽, 我是测试2")# 全局的函数调用test1()

在PyCharm中,当模块hello.py被直接运行时,输出结果如下:

e18694a8976c2ed6b59bb9255d1944cb.png

在PyCharm中,当模块hello.py被导入多次,代码如下:

import helloimport helloimport helloprint(hello.name)

然后,运行这段代码,结果如下:

96932b730691a6ec573fc9f75db44307.png

在Python自带的IDLE中也试试,进行多次导入:

e65a0ec65681a896bb5eebdc0e72ab58.png

通过3次不同的实验,说明以下结论:

1)当模块第1次被导入时,才被加载并执行模块内的语句。

2)以后再次导入模块时,Python解释器会判断模块是否被加载,如果已经被加载,则不会再执行加载过程,而是通过模块名直接引用已经加载的模块。

3)模块直接运行时的__name__的值是字符串“__main__”,模块被导入时的__name__的值是模块的名称(如果模块在是某个包中,__name__模块的名字有什么不同?小伙伴可以自己试试)。

因此,在模块文件中,不要出现全局的函数调用,因为全局的函数调用在加载时被直接执行。有小伙伴说,“写完一个模块,需要进行一个简单的测试,需要调用这些函数,怎么办?”这时候,根据上面的结论3),可以在下面的if语句中调用。

if __name__ == "__main__":    # 在这里写相关的函数调用    pass

修改后的模块hello.py的代码如下:

#!/usr/bin/python3# -*- coding: utf-8 -*-name = "hello.py"def test1():    print("哈喽, 我是测试1")    def test2():    print("哈喽, 我是测试2")if __name__ == '__main__':    '''    测试相关的代码写在这里,不要写在顶层的全局代码区    '''    print("各位请注意,我来啦")    test1()

3、 模块的导入顺序

推荐所有的模块在Python模块的开头部分导入,一行导入一个模块。并且按照以下的导入顺序:

1)Python内置模块; 2)Python第三方模块; 3)自定义模块; 03 模块的搜索路径

一个模块就是一个.py文件,当我们进行模块导入时,Python解释器是从哪里查找这个模块文件呢?

平时,我们安装一些开发软件时,会遇到添加到Path环境变量的选项,如果我们勾选后,当运行一些小工具时,直接在cmd窗口,输入工具的文件名称,回车就可以打开这个工具,比如我们的安装Python时,就有这个选项。如果没有勾选添加到环境变量,就要在工具所在的文件夹目录打开命令行窗口,输入工具的文件名称,回车才可以打开工具。

因此,Python查找模块文件时,很有可能也会在Path环境变量或是当前文件所在的文件夹目录中查找。事实上,Python确实会从这些位置查找模块文件,但是还有其他的一些目录,并遵循一定的搜索顺序。具体如下:

1)内存中查找是否存在要导入的模块,也就是查看模块是否已经加载过。

2)如果没加载过,在Python内置模块中查找;

3)如果没找到,当前执行文件所在的目录查找;

4)如果没找到,在sys.path所代表的环境变量指定的一系列目录中查找;

5)如果还没有找到,则Python抛出异常。

下面以hello模块为例,演示了这一查找过程。在实际开发过程中,如果我们的模块文件在其他文件夹,就需要使用sys.path.append()的方式添加,否则会弹出模块找不到的异常。

2e4ccdfd22606d5de8d689e01afdbcc0.png

04 包

包,是一个包含其它模块或子包的目录。在Python3.3之前,目录下必须要有一个__init__.py文件,这个目录才被Python视为包。通常这个__init__.py文件是一个空文件。但在Python3.3及以后的版本,任何一个目录都可以被视为包,目录里可以有__init__.py文件,也可以没有。

一个典型的包的结构如下,这个包的名称是pkg1,包含3个子模块:mod1, mod2,  mod3:

a61bce8347976beaf66255a6220a3d50.png

包有助于模块的结构化管理,在开发过程中,一个项目可能会有成百上千个Python文件,如果全放在一个文件夹里面,既不方便查找,也不方便管理。这时,包就派上用场了,可以建立层次化的包(目录)结构,把这些模块进行分类,功能相同或相关的模块放在一个目录(包)。

此外,一个软件项目,是由很多开发者共同开发,开发者A开发功能点1,开发者B开发功能点2,这2个开发者可以各自建立一个包,并把开发完成的模块放在包里面,即使2个开发者的模块名称相同,由于包名不同,访问时是由包名+模块名的方式访问,这也能解决模块名称冲突的问题。因此,使用包可以方便开发者进行协作开发。

1、 包的使用

包也是一种特殊的模块,和其它模块一样,包也使用包名+点号+标识符的方式访问属性。使用import或者from-import语句导入包中的模块。

对于上面的包pkg1中的模块1,定义了如下的函数:

# -*- coding: utf-8 -*-def mod1_test():print("我是模块1的函数")

导入和访问包中的模块,有如下方式:

1)import语句导入模块

# 导入模块import pkg1.mod1# 使用模块pkg1.mod1.mod1_test()

这种方式,调用模块的属性时,有很长的名称限制,比较繁琐,这时就可以使用from-import语句

2)From Import语句导入模块

# 导入模块from pkg1 import mod1# 使用模块mod1.mod1_test()

3)From Import语句导入模块中的具体属性

# 直接导入模块中的函数from pkg1.mod1 import mod1_test# 使用模块中的函数mod1_test()

注意:除了使用上面的标准方式访问模块或属性,还可以使用as来指定别名,小伙伴可以自己试试。

05 写在最后

能够应用到实际工作中的知识才是有价值的知识。前面出现问题的小帅同学,飞哥特别叮嘱他消化一下模块和包的知识,并把前面的那张模块结构划分的图发给他,让他进行重构。过了1天,小帅发给飞哥修改后的代码,“优化掉20%的代码量,1个主文件完成模块的导入和功能的调用,3个模块文件分别完成文件读取数据、数据处理以及数据库操作。现在的代码结构很清晰,每个模块的功能独立。”

更多Python精彩文章、新手学习干货,欢迎一起交流学习!

END 6c0bf949bc8de35e6c8c85f2e78361e6.gif 扫码关注我们 096f6d27ef536e54ea252dfdab1f9f10.png 专业提供 定制学习计划和职业规划服务 公众号:Python编程研习社 6c0bf949bc8de35e6c8c85f2e78361e6.gif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当在vscode中运行Python代码时出现ImportError: DLL load failed: 找不到指定的模块的错误,通常是由于缺少所需的库或模块导致的。根据引用和引用[2]的描述,出现这个错误的原因可能是缺少了OpenCV库或scikit-image库。而根据引用的描述,您在创建虚拟环境时可能没有正确地安装numpy库。 解决这个问题的方法是确保您安装了所需的库,并且路径配置正确。首先,您可以尝试使用pip命令或conda命令重新安装OpenCV库和scikit-image库,确保安装的版本与您的Python环境兼容。例如,使用以下命令安装OpenCV库: pip install opencv-python 然后,您可以使用以下命令安装scikit-image库: pip install scikit-image 接下来,您需要检查您的Python环境变量是否正确设置。确保将Python及其相关的库的路径添加到系统的环境变量中。您可以通过在命令提示符下运行以下命令来检查Python路径: python -c "import sys; print(sys.path)" 如果您发现路径不正确或缺少所需的库路径,您可以通过编辑环境变量来添加正确的路径。 最后,您还可以尝试重新启动vscode,然后再次运行您的代码,看看问题是否得到解决。 总结起来,解决vscode运行Python代码时出现ImportError: DLL load failed: 找不到指定的模块的错误,您可以尝试以下步骤: 1. 使用pip或conda重新安装缺少的库,比如OpenCV和scikit-image。 2. 检查Python环境变量是否正确设置,并添加所需库的路径。 3. 重新启动vscode并再次运行代码。 希望这些步骤能够帮助您解决问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [python ImportError: DLL load failed while import cv2: 找不到指定的模块。](https://download.csdn.net/download/zz975896590/85710278)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [运行 skimage 报错ImportError: DLL load failed:找不到指定模块](https://blog.csdn.net/fanlily913/article/details/120130357)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [vscode虚拟环境运行文件报错ImportError: DLL load failed: 找不到指定的模块的问题](https://blog.csdn.net/yukiter1221/article/details/123193245)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值