• python中的模块


    一、概论

    模块支持从逻辑上组织python代码。

    当代码量变得相当大的时候,我们最好把代码分成一些有组织的代码段,前提是保证它们的彼此交互。

    把其他模块中属性附加到你的模块中的操作叫做导入(import),那些自我包含并且有组织的代码片段就是模块(module)。

    如果说模块是按照逻辑来组织python代码的方法,那么文件便是物理层上组织模块的方法。

    因此,一个文件被看作是一个独立的模块,一个模块也可以被看作是一个文件,模块的文件名就是模块的名字加上扩展名.py.

    一个名称空间就是一个从名称到对象的关系映射集合,模块名称是它们的属性名称中一个重要的部分。

    向名称空间添加名称的操作过程涉及绑定标识符到指定对象的操作(以及给该对象的引用计数加1)。

    改变一个名字的绑定叫做重新绑定,删除一个名字叫做重新绑定。如果在执行期间调用了一个函数,那么将创建局部名称空间。

    给定一个模块名之后,只可能有一个模块被导入到python解释器,所以在不同的模块间不会出现名称交叉的现象,故而每个模块都定义了它自己的唯一的名称空间。

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

    import语句可以在程序中的任意位置使用的。

    第一次导入后就将模块名加载到内存了,后续的import语句仅是对已经加载到内存中的模块对象增加一次引用。所以当以重复导入的时候,并不会出现问题。

    我们可以从sys.modules中找到当前已经加载的模块,sys.modules是一个字典,内部包含模块名与模块对象的映射,该字典决定了导入模块时是否需要重新导入。

    首次导入模块my_module时会做三件事:

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

    (2)在新建的名称空间中执行模块中包含的代码,即初始导入import my_module。这个过程就是将模块中的函数名放入模块全局名称空间表。

    (3)创建名字my_module来引用该命名空间

    二、导入

    1.import语句

    使用import语句导入模块

    >>> import os
    >>> import math

    也可以在一行之内导入多个模块,就像这样

    >>> import os,time,random

    下面这样导入,代码的可读性不如多行导入语句。

    解释器执行完导入语句之后,如果在搜索路径找到了指定的模块,就会加载它。

    该过程遵循作用域原则,如果在一个模块的顶层导入,那么它的作用域是全局的,如果在函数中导入,那么它的作用域是局部的。

    如果模块是第一次被导入,它将被加载并执行。

    2.from-import语句

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

    >>> from time import time,localtime
    >>> time()
    1510832882.9023538
    >>> localtime()
    time.struct_time(tm_year=2017, tm_mon=11, tm_mday=16, tm_hour=19, tm_min=48, tm_sec=7, tm_wday=3, tm_yday=320, tm_isdst=0)

    还可以导入所有,就像这样

    >>> listdir('/')
    ['boot', 'dev', 'proc', 'run', 'sys', 'etc', 'root', 'var', 'tmp', 'usr', 'bin', 'sbin', 'lib', 'lib64', 'home', 'media', 'mnt', 'opt', 'srv', 'backup', 'Python-3.6.3.tar.xz', 'Python-3.6.3', 'script', 'test', 'zuoye']
    >>> getcwd()
    '/root'

    from my_module import *把my_module中所有的不是下划线(_)开头的名字都会导入到当前位置,这不是一个好的选择。

    它会“污染”当前名称空间,而且很有可能覆盖当前名称空间中现有的名字。

    在两种场合下建议使用这样的方法,一个场合是:目标模块的属性非常多,反复键入模块名很不方便;

    还有一个场合就是在交互式解释器下,因为这样可以减少输入次数。

    3.扩展的import语句(as)

    有时候你导入的模块或是模块属性名称已经在你的程序中使用了,或者你不想使用导入的名字,你想使用自己想要的名字替换掉模块的原始名称,这时你可以使用as。

    >>> import random as ra
    >>> ra.randint(10,100)
    30

    使用场景:

    (1)模块的名称太长

    (2)名称空间有冲突

    (3)当兼容多个模块的相同操作的时候。

    三、编译

    1.模块的搜索路径

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

    >>> import sys
    >>> sys.modules
    {'builtins': <module 'builtins' (built-in)>, 'sys': <module 'sys' (built-in)>, '_frozen_importlib': <module '_frozen_importlib' (frozen)>, '_imp': <module '_imp' (built-in)>, '_warnings': <module '_warnings' (built-in)>, '_thread':.....

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

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

    模块查找的顺序:内存中已经加载的模块——》内置模块——》扩展模块——》自定义模块。

    在初始化后,python程序可以修改sys.path路径,路径放在前面的优先加载

    2.编译python文件

    为了提高加载模块的速度,提高的是加载速度而绝非运行速度。

    python解释器会在__pycache__目录下缓存每个模块编译后的版本格式为:module.version.pyc。

    python检查源文件的修改时间与编译时间的版本进行对比,如果过期就需要重新编译。

    这是完全自动的过程。并且编译的模块是平台独立的,所以相同的库可以在不同的架构的系统之间共享,即pyc是一种跨平台的字节码。

    python解释器会在一下两种情况下不检查缓存。

    1.如果是在命令行中被直接导入模块,则按照这种方式,每次导入都会重新编译,并且不会存储编译后的结果(python3.3以前)。

    2.如果源文件不存在,那么缓存的结果也不会被使用,如果想在没有源文件的情况下来使用编译后的结果,则编译后的结果必须在源目录之下。

    注意事项:

    (1)模块名区分大小写,foo.py与FOO.py代表的是两个模块。

    (2)你可以使用-O或者--OO转换python命令来减少编译模块的大小。

    (3)在速度上从.pyc文件中读取指令来执行不会比.py文件中读指令执行更快,只有在模块被夹在时,.pyc文件才是更快的。

    (4)只有使用import语句才会将文件自动编译为.pyc文件,在命令行或标准输入中指定运行脚本则不会生成这类文件,因而我们可以使用compieall模块为一个目录中的所有模块创建.pyc文件。

    (5)如果在模块中使用__name__这个变量,则在调用的时候要指定名字。

  • 相关阅读:
    在linux上使用Android systrace
    perf性能调优
    未初始化内存检测(MSan)
    数据竞争检查工具(TSan)
    应用层内存溢出/越界/重复释放等问题检查工具(ASan)
    gperf heap profiler
    cmake打印shell
    github clone加速
    获取一个进程的所有物理地址上的内存
    Jenkins <1>: System Management
  • 原文地址:https://www.cnblogs.com/yangmingxianshen/p/7846421.html
Copyright © 2020-2023  润新知