Loading

模块基础

Python文件的两种运行方式

1、脚本方式:

  • 直接解释器执行。

2、模块方式:

  • 通过导入语句被其他文件导入,为导入它的文件提供资源(变量,函数定义,类定义等)。

模块的定义

  • 本质就是文件,一系列功能的集合体。
  • 模块中出现的变量,for循环,if结构,函数定义。。。等称为模块的成员。

对一些通用的功能,将它们提出来放进一个模块中,然后在各个地方导入使用,这样能增加开发效率,减少代码冗余。


模块的四种通用的类别

1、一个Python文件就是一个模块,文件名test.py,模块名则为test。

2、盛放有多个Python文件的目录也是一个功能的集合体,也是一种模块,称之为包。

3、已被编译为共享库或DLL或C++扩展。

4、使用C编写并链接到Python解释器的内置模块。


模块的三种来源

1、自带的模块。

  • 内置模块,集成在解释器内部。

    import time
    print(time)
    <module 'time' (built-in)>
    
  • 标准库

    import os
    print(os)
    <module 'os' from 'D:\\Python38\\lib\\os.py'>
    

2、第三方模块

一些开发者写的非常好的模块,需要同过pip命令安装的模块,比如Django。

3、自定义模块。

我们自己写的一些模块。

模块导入

模块导入的两种语句:

import 模块名
from 模块名 import 成员

第一种的优点是能指名道姓的使用该模块的成员,不会产生名称冲突;缺点是每次使用都要加模块名前缀。

第二种的优点是使用简单,不用加模块名前缀;缺点是容易与当前命名空间的名称产生冲突。


模块导入的多种方式

导入一个模块的所有成员。

import module

一次性导入多个模块的所有成员,不推荐这种写法。

import module1, module2,module3......

从某个模块中导入指定的成员。

from module import a

从某个模块中导入多个成员。

from module import a,b,c

从模块中导入所有成员,和import的区别是这种方式不用加模块名前缀。

from module import * 

使用from module import * 控制成员被导入

  • 默认情况下,所有成员都会被导入。
  • __all__是一个列表,用于表示本模块可以被外界使用的成员,元素是成员名组成的字符串。
# 在模块内使用'__all__'控制被导入的成员。

__all__ = [member1,member2,member3,...]

在文件中使用from module import *导入时,只能使用列表内的成员,若要使用模块的所有成员,可以不使用from module import * ,从而绕过__all__的限制。


怎么解决命名冲突的问题

  • 使用import module 导入。
  • 自己避免使用同名的名称。
  • 使用别名解决冲突。

模块别名

主要针对导入的模块和导入模块的成员,并非针对我们自己写的变量、函数、类等

1、给成员起别名,避免命名冲突。

form module import  member as mem_alias

2、给模块起别别名,简化书写。

import module as mod_alias

as是alias的缩写。


模块使用

使用模块名加点.方式来调用模块下的成员。

import time
print(time.time()) # 表示使用time模块中的time()方法

首次导入模块发生的事

  • 1、在内存中产生模块的名称空间,将模块运行的过程中产生的名字都丢到模块的名称空间中。
  • 2、执行模块名称空间中所有可执行代码。
  • 3、在当前文件中产生一个模块名称,该名称指向模块中产生的名称空间 。

导入语句可以在程序中任意位置使用,为防止针对同一模块的多次导入重复占用内存空间,Python的优化手段是:

第一次导入后就将模块名加载到内存了,后续的import语句进是针对已经加载到内存的模块对象增加了一次引用,不会重复执行模块内的语句


导入后的名称空间

  • 被导入的模块有独立的名称空间,无论是查看还是修改操作的都是原模块,与调用位置无关
  • 模块的名称空间没有被引用后,则会被回收。
  • 模块也可以在函数中导入,导入后则只能在导入时的名称空间内使用,函数执行完毕后则名称空间被回收。
def func():
    import time
    print(time.time())
# 函数外则无法调用
time.time()

模块的导入规范

约定俗称的顺序,便于读代码

  • 1、内置模块。
  • 2、第三方模块。
  • 3、自定义模块。

循环导入问题

指的是模块之间互相导入。例如,

# 模块1中导入模块2。
from m2 import n
i = 1

# 模块2中导入模块1。
from m1 import i
n = 2

如果这时候,我们要在另一个执行文件中导入其中一个模块,就会报错。

import m1

ImportError: cannot import name 'i' from partially initialized module 'm1' (most likely due to a circular import)

这是因为,在当前文件导入m1时,m1的代码执行导入m2,m2的代码执行又导入m1中的变量i,但此时变量i在m1中还没有定义(因为第一行from还没有执行完毕),所以会报错无法导入i

首先,循环导入在构建代码逻辑时是一定要避免的,但若你的代码逻辑走到这一步,那么解决方式有4种:

1、在导入模块前定义名称。

n = 2
from m1 import i

2、将导入模块语句写在函数中,之后的函数调用在定义名称之后。

def func():
    from m1 import i
    
n = 2
func()

3、使用一个新文件,将俩模块公用部分放入新文件中。

4、使用import导入也能避免该问题。

控制模块被导入时是否运行

一个模块往往包含多个功能,自定义模块被其他模块导入时,其中的可执行语句会立即执行,一般我们不希望模块内的函数直接执行,仅在需调用其中某些功能时才执行,解决方式是使用全局变量 _name_。

  • 当文件被当做脚本执行时,在文件内执行 print( _name_) 返回值是固定字符串 '__main__',表示当前是开发模式。
print(__name__)

__main__
  • 当文件被当做模块导入时,在模块内的 _name_ 等于模块原名(不包含.py后缀),表示当前是导入模式。
# 在模块中判断__name__是否为'__main__'
import time
print(time.__name__)
time

使用__name__这个特性帮我们区分模块的两种运行方式:

def func():
    pass

if __name__ == '__main__':
    func()
    # 如果为True则表示是开发模式,则执行函数。
    # 如果为False则是导入模式,则不会执行

此语句经常使用,Pycharm提供了一个快捷方式,直接输入 main 然后回车即可。

模块的搜索路径优先级

Python中导入模块是按照一定的规则以及顺序去寻找的。

1、内存中

  • 如果之前成功导入过某个模块,则直接使用已经存在的模块。
# sys.modules查看已经加载到内存中的模块

import sys
print(sys.modules)

输出为一个字典,模块名为key,value是导入位置

2、内置模块

  • Python解释器的安装路径中Lib目录下,所有以 .py结尾的文件,都是自带模块。
  • Lib目录中的site-packages目录,一些来源网络的第三方模块,就放在这个目录中。

3、sys.path路径

  • 是一个路径的列表。通常导入自定义的模块时,将自定义模块的目录添加至此列表中。
import sys
print(sys.path)

# ['D:\\Desktop\\Netfile\\Python\\Program\\Py_programs', 
'D:\\Desktop\\Netfile\\Python\\Program\\Py_programs', 'D:\\PyCharm 
2020.1.1\\plugins\\python\\helpers\\pycharm_display', 'D:\\Python38\\python38.zip', 
'D:\\Python38\\DLLs', 'D:\\Python38\\lib', 'D:\\Python38', 
'D:\\Python38\\lib\\site-packages', 'D:\\PyCharm 
2020.1.1\\plugins\\python\\helpers\\pycharm_matplotlib_backend']

第一个路径是当前执行文件的所在目录,第二个目录在pycharm中的话,它会做一个优化,将当前项目这个顶级目录也添加入sys.path列表中。


添加模块所在目录的绝对路径

对于我们自定义的模块或下载的第三方模块,如果模块的所在目录不在sys.path列表中,那么就不能直接导入,解决方式就是在列表中添加模块所在目录的路径。

sys.path.append(r'/path/moudir')

sys.path添加路径是临时添加,程序运行结束后恢复。

sys.path环境变量是以执行文件为准的,被导入的模块或后续其他文件引用的sys.path都是参照执行文件的sys.path。

import sys

sys.path.append('abcdefghijklmnopqrstuvwxyz')
print(sys.path)

import modu1     # modu1中有一行print(sys.path)语句
print('下面是模块的sys.path.............')

结果为:

['D:\\Desktop\\Netfile\\Python\\Program\\Py_programs', 'D:\\Desktop\\Netfile\\Python\\Program\\Py_programs', 'D:\\PyCharm 2020.1.1\\plugins\\python\\helpers\\pycharm_display', 'D:\\Python38\\python38.zip', 'D:\\Python38\\DLLs', 'D:\\Python38\\lib', 'D:\\Python38', 'D:\\Python38\\lib\\site-packages', 'D:\\PyCharm 2020.1.1\\plugins\\python\\helpers\\pycharm_matplotlib_backend', 'abcdefghijklmnopqrstuvwxyz']

下面是模块的sys.path.............

['D:\\Desktop\\Netfile\\Python\\Program\\Py_programs', 'D:\\Desktop\\Netfile\\Python\\Program\\Py_programs', 'D:\\PyCharm 2020.1.1\\plugins\\python\\helpers\\pycharm_display', 'D:\\Python38\\python38.zip', 'D:\\Python38\\DLLs', 'D:\\Python38\\lib', 'D:\\Python38', 'D:\\Python38\\lib\\site-packages', 'D:\\PyCharm 2020.1.1\\plugins\\python\\helpers\\pycharm_matplotlib_backend', 'abcdefghijklmnopqrstuvwxyz']

posted @ 2020-07-22 09:21  吃了好多肉  阅读(183)  评论(0编辑  收藏  举报