模块

---恢复内容开始---

一 模块

1 什么是模块?

    一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。

2 为何要使用模块?

    如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script。

    随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用

3.如何使用模块?

  3.1 import

#spam.py
print('from the spam.py')

money=1000

def read1():
    print('spam->read1->money',1000)

def read2():
    print('spam->read2 calling read')
    read1()

def change():
    global money
    money=0

   3.1.1模块可以包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次遇到导入import语句时才执行

#test.py
import spam #只在第一次导入时才执行spam.py内代码,此处的显式效果是只打印一次'from the spam.py'
import spam
import spam
import spam

'''
执行结果:
from the spam.py
'''

  3.1.2 每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个模块的名称空间当做全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量会在被导入时,与使用者的全局变量冲突

#测试一:money与spam.money不冲突
#test.py
import spam 
money=10
print(spam.money)

'''
执行结果:
from the spam.py
1000
'''

#测试二:read1与spam.read1不冲突
#test.py
import spam
def read1():
    print('========')
spam.read1()

'''
执行结果:
from the spam.py
spam->read1->money 1000
'''

#测试三:执行spam.change()操作的全局变量money仍然是spam中的
#test.py
import spam
money=1
spam.change()
print(money)

'''
执行结果:
from the spam.py
1
'''

  3.1.3 总结:首次导入模块spam时会做三件事:

    

    1.为源文件(spam模块)创建新的名称空间,在spam中定义的函数和方法若是使用到了global时访问的就是这个名称空间。

    2.在新创建的命名空间中执行模块中包含的代码,见初始导入import spam

    3.创建名字spam来引用该命名空间

3.2 from ... import...

  对比import spam,会将源文件的名称空间'spam'带到当前名称空间中,使用时必须是spam.名字的方式

而from 语句相当于import,也会创建新的名称空间,但是将spam中的名字直接导入到当前的名称空间中,在当前名称空间中,直接使用名字就可以了、

1 from spam import read1,read2

3.3 把模块当做脚本执行

我们可以通过模块的全局变量__name__来查看模块名:
当做脚本运行:
__name__ 等于'__main__'

当做模块导入:
__name__=

作用:用来控制.py文件在不同的应用场景下执行不同的逻辑
if __name__ == '__main__':

#fib.py

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print(b, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while b < n:
        result.append(b)
        a, b = b, a+b
    return result

if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))

3.4 模块搜索路径

python解释器在启动时会自动加载一些模块,可以使用sys.modules查看

在第一次导入某个模块时(比如spam),会先检查该模块是否已经被加载到内存中(当前执行文件的名称空间对应的内存),如果有则直接引用

如果没有,解释器则会查找同名的内建模块,如果还没有找到就从sys.path给出的目录列表中依次寻找spam.py文件。

所以总结模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块

需要特别注意的是:我们自定义的模块名不应该与系统内置模块重名。虽然每次都说,但是仍然会有人不停的犯错。

3.5 编译python文件

为了提高模块的加载速度,Python缓存编译的版本,每个模块在__pycache__目录的以module.version.pyc的形式命名,通常包含了python的版本号,如在CPython版本3.3,关于spam.py的编译版本将被缓存成__pycache__/spam.cpython-33.pyc,这种命名约定允许不同的版本,不同版本的Python编写模块共存。

Python检查源文件的修改时间与编译的版本进行对比,如果过期就需要重新编译。这是完全自动的过程。并且编译的模块是平台独立的,所以相同的库可以在不同的架构的系统之间共享,即pyc使一种跨平台的字节码,类似于JAVA火.NET,是由python虚拟机来执行的,但是pyc的内容跟python的版本相关,不同的版本编译后的pyc文件不同,2.5编译的pyc文件不能到3.5上执行,并且pyc文件是可以反编译的,因而它的出现仅仅是用来提升模块的加载速度的。

3.6  标准模块

python提供了一个标准模块库,一些模块被内置到解释器中,这些提供了不属于语言核心部分的操作的访问,但它们是内置的,无论是为了效率还是提供对操作系统原语的访问。这些模块集合是依赖于底层平台的配置项,如winreg模块只能用于windows系统。特别需要注意的是,sys模块内建在每一个python解释器

sys.ps1
sys.ps2
这俩只在命令行有效,得出的结果,标识了解释器是在交互式模式下。


变量sys.path是一个决定了模块搜索路径的字符串列表,它从环境变量PYTHONOATH中初始化默认路径,如果PYTHONPATH没有设置则从内建中初始化值,我们可以修改它
sys.path.append

import os
os.path.normpath(path)  #规范化路径,转换path的大小写和斜杠

a='/Users/jieli/test1/\a1/\\aa.py/../..'
print(os.path.normpath(a))
'''
打印结果:
Usersjieli	est1
'''


#具体应用
import os,sys
possible_topdir = os.path.normpath(os.path.join(
    os.path.abspath(__file__),
    os.pardir, #上一级
    os.pardir,
    os.pardir
))
sys.path.insert(0,possible_topdir)

os一种好的处理路径的方式

3.7  dir()函数

内建函数dir是用来查找模块中定义的名字,返回一个有序字符串列表
import spam
dir(spam)

如果没有参数,dir()列举出当前定义的名字


dir()不会列举出内建函数或者变量的名字,它们都被定义到了标准模块builtin中,可以列举出它们,
import builtins
dir(builtins)

原文地址:https://www.cnblogs.com/xuzheng940806/p/6798804.html