python导入模块的方法有哪些

发布网友 发布时间:2022-04-23 20:11

我来回答

3个回答

懂视网 时间:2022-04-06 06:20

Python视频教程栏目今天为大家介绍学习Python模块导入机制与大型项目的规范。

前言

在我们平常工程里使用Python的过程中,经常需要解决各个模块的导入问题,而且也常常遇到引用路径查找不到、交叉导入模块等等问题,故写这篇文章,旨在讲述Python的模块导入机制和我们平时大型项目中应该遵循的模块导入规范

Python模块导入

日常编程中,为了能够复用写过的代码逻辑,我们都会把这些代码封装成为模块,需要用到的时候可以直接导入复用,以便提高我们的开发效率。 module能定义函数、类、变量,也能包含可执行的代码。module来源有3种: ①Python内置的模块(标准库); ②第三方模块; ③自定义模块;

导入原理

模块的导入一般是在文件头使用import关键字,import一个模块相当于先执行了一次这个被导入模块,然后在本命名空间建立一个与被导入模块命名空间的联系,相当于在本命名空间新建了一个变量,这个变量名称是被导入模块的名称,指向被导入模块的命名空间。所以导入的这个模块相当于一个变量,因此多次导入同一个模块只有第一次导入的时候会被执行(后续导入会判断到这个模块变量已存在所以不执行)

997346e5c5df4251ab8633d317077cc5_tplv-k3u1fbpfcp-zoom-1.png

路径查找机制

每一个导入的模块都会在Python内置字典sys.modules中,Python一启动,它将被加载在内存中,当我们导入新modules,sys.modules将自动记录下该module。 Python的模块查找路径的机制是:

  1. 查找sys.path中的所有路径下是否有该模块,有则开辟新空间加载该模块;
  2. 查看sys.modules中是否有内置包或已安装的第三方包,有则开辟新空间加载该模块;

所以对于我们自己编写的模块,如果封装并发布到了PyPi,则可以用pip install直接安装,并在启动时加载在内存中,通过sys.modules可以查看到 而对于仅需要在本项目中复用的模块,我们在复用代码中将其路径加入到sys.path中,同样可以引用到该模块。

绝对路径导入

所有的模块import都从“根节点”开始。根节点的位置由sys.path中的路径决定,项目的根目录一般自动在sys.path中。如果希望程序能处处执行,需手动修改sys.path

import sys,os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))#项目根目录所在的绝对路径sys.path.append(BASE_DIR)import A, B #导入A、B包复制代码

相对路径导入

只关心相对自己当前目录的模块位置就好。不能在包(package)的内部直接执行(会报错)。不管根节点在哪儿,包内的模块相对位置都是正确的。

#from . import b2 #这种导入方式会报错,只有在包内部直接执行的时候才可以这样导入。import b2#正确b2.print_b2()复制代码

Python模块导入常见问题

  • 单独import某个包名称时,不会导入该包中所包含的所有子模块 解决办法:导入的包中也包含了其他包的导入,此时需要在每个包的init.py文件中导入该包下的所有模块,最上层才可以直接引用最下层的包的类和方法
  • init文件

    当一个文件夹下有init.py时,意为该文件夹是一个包(package),其下的多个模块(module)构成一个整体,而这些模块(module)都可通过同一个包(package)导入其他代码中。 其中init.py文件 用于组织包(package),方便管理各个模块之间的引用、控制着包的导入行为。

    该文件可以什么内容都不写,即为空文件(为空时,仅仅用import [该包]形式 是什么也做不了的),存在即可,相当于一个标记。

    在python3中,即使包下没有init.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包会报错

    all变量

    all 是一个重要的变量,用来指定此包(package)被import *时,哪些模块(module)会被import进【当前作用域中】。不在all列表中的模块不会被其他程序引用。可以重写all,如 all= [‘当前所属包模块1名字’, ‘模块1名字’],如果写了这个,则会按列表中的模块名进行导入

    name变量

    在包内部直接运行时,包的name == 'main',但是在外部导入包是,可以通过

    if __name__ == '__main__':复制代码

    来避免实现包内部调试时的逻辑

    循环导入

    当两个模块A和B之间相互import时,就会出现循环导入的问题,此时程序运行会报错:can not import name xxx,如:

    # a.pyprint('from a.py')from b import x
    
    y = 'a'复制代码
    # b.pyprint('from b.py')from a import y
    
    x = 'b'复制代码

    我们来分析一下这种错误是怎么出现的:

    1. 在sys.modules中查找 符号“module b”;
    2. 如果符号“module b”存在,则获得符号“module b”对应的module对象; 从的dict中获得 符号“x”对应的对象。如果“x”不存在,则抛出异常“ImportError: cannot import name ‘x’”
    3. 如果符号“module b”不存在,则创建一个新的 module对象。不过此时该新module对象的dict为空。然后执行module b.py文件中的语句,填充的dict。

    因此在a.py中执行from b import x的顺序就是1->3,先引入b,b里面from a import y由相当于执行了a.py,顺序是1->2,因为此时b已经引入所以不会执行3,2中无法找到x对象,因为引入b时还没执行到x='b'这一步,所以报错了

    解决办法

    1. 延迟导入,把import语句写在方法/函数里,将它的作用域在局部;
    2. 顶层先引入模块,再把from x import y改成import x.y形式;
    3. 其实出现循环引用问题的根本原因是程序设计不合理,每个包都应该由上层使用的模块去导入,而不应该在包与包之间各种相互导入,所以应该更改代码布局,可合并或分离竞争资源;

    大型项目中Python模块导入规范

    分离模块,将同一类别的模块放在同一目录下,形成类别分明的目录架构,如:

    0019951058714d4fb329ac2c37e7905d_tplv-k3u1fbpfcp-zoom-1.png

    1. 每一个模块目录都要写init.py文件,可以同时定义all限定可导入的范围;
    2. 源码根目录可以定义BASE_DIR,限定好根目录路径,启动py文件可以用绝对路径导入各个模块,将必要模块都加入到sys.path中;
    3. 各个服务之间(例如model需要引入common的模块方法),可以通过相对路径引用模块;
    4. 程序设计时避免循环导入,可由调用者(服务文件)作为上层第三方引入需要的各个模块,这样就可以减少各个模块的相互导入。

    更多相关免费学习推荐:python视频教程

    热心网友 时间:2022-04-06 03:28

    方法一
    import modname
    模块是指一个可以交互使用,或者从另一Python 程序访问的代码段。只要导入了一个模块,就可以引用它的任何公共的函数、类或属性。模块可以通过这种方法来使用其它模块的功能。
    用import语句导入模块,就在当前的名称空间(namespace)建立了一个到该模块的引用.这种引用必须使用全称,也就是说,当使用在被导入模块中定义的函数时,必须包含模块的名字。所以不能只使用 funcname,而应该使用 modname.funcname

    方法二
    from modname import funcname
    from modname import fa, fb, fc
    或者
    from modname import *
    与第1种方法的区别:funcname 被直接导入到本地名字空间去了,所以它可以直接使用,而不需要加上模块名的限定* 表示,该模块的所有公共对象(public objects)都被导入到 当前的名称空间,也就是任何只要不是以”_”开始的东西都会被导入。
    modname没有被定义,所以modname.funcname这种方式不起作用。并且,如果funcname如果已经被定义,它会被新版本(该导入模块中的版本)所替代。如果funcname被改成指向其他对象,modname不能不会觉察到。
    建议:
    1)如果你要经常访问模块的属性和方法,且不想一遍又一遍地敲入模块名,使用 from mole import
    2)如果你想要有选择地导入某些属性和方法,而不想要其它的,使用 from mole import
    3)如果模块包含的属性和方法与你的某个模块同名,你必须使用import mole来避免名字冲突
    4)尽量少用 from mole import * ,因为判定一个特殊的函数或属性是从哪来的有些困难,并且会造成调试和重构都更困难。

    方法三
    内建函数__import__()
    除了前面两种使用import关键字的方法以外,我们还可以使用内建函数 __import__() 来导入 mole。两者的区别是,import 后面跟的必须是一个类型(type),而__import__() 的参数是一个字符串,这个字符串可能来自配置文件,也可能是某个表达式计算结果。例如:
    mymole = __import__ (’mole_name’)
    附注:
    1)模块的内容都放在一个模块文件中,如 mymole 的内容应该放在PYTHONPATH 目录下的一个mymole.py中,C实现的除外
    2)包可以将几个模块名称空间组织起来, 如A.b 就表示在包A中的一个子模块b
    可以单独导入某一个子模块,如Python文档中给出的例子
    import sound.effects.echo
    这样必须使用全称对里面的对象进行引用,如
    sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
    还可以使用下面的语句来加载echo子模块
    from Sound.Effects import echo
    它在没有包前缀的情况下也可以使用, 所以它可以如下方式调用:
    echo.echofilter(input, output, delay=0.7, atten=4)
    不主张从一个包或模块中用import * 导入所有模块,因为这样的通常会导致可读性很差。
    from Package import specific_submole的用法并没有错,实际上这还是推荐的用法,除非导入的模块需要使用其它包中的同名子模块(the importing mole needs to use submoles with the same name from different packages).
    综上所述,一般情况应该使用import , 但有几个例外
    1)mole文档告诉你要用from-import的
    2)导入一个包组件。需要一个包里面的某个子模块,一般用from A.b import c比import A.b.c 更方便 且不会冒混淆的危险.

    热心网友 时间:2022-04-06 04:46

    from ... import ...
    import ...
    from ... import*
    就这些

    声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com