zoukankan      html  css  js  c++  java
  • Python模块化

    1、模块化

    一般来说,编程语言中,库、包、模块是一种概念,是代码组织方式。

    Python中只有一种模块对象, 但是为了模块化组织模块的便利,提供了一个概念--包模块module,指的是Python的源代码文件。

    包package,指的是模块组织在一起和包名同名的目录及其相关文件。

    2、导入语句

    语句

    含义

    Import模块1[模块2]

    完全导入

    Import...as.....

    模块别名

    Import 的作用:将需要的模块的名称引用到当前所有的模块的名词空间中。

    加载到了sys.modules里面去了。

    from (后面是模块)import(类、函数)

    from pathlib import *

    from子句中指定的模块,加载并初始化,(并不是导入)。

    Import语句:

    (1)找到指定的模块,加载并初始化他,生成模块对象。找不到,抛出importError异常。

    (2)Import所在的作用域的局部命名空间内,增加名称和上一步创建的对象关联。

    import functools
    print(dir())
    print(functools)
    print(functools.wraps)

    1,['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'functools']

    2,<module 'functools' from 'C:\Users\WCL\AppData\Local\Programs\Python\Python35\lib\functools.py'>

    3,<function wraps at 0x00000018C691F620>

    import os.path
    print(1,dir())
    print(2,os)
    print(3,os.path)

    1 ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'os']

    2 <module 'os' from 'C:\Users\WCL\AppData\Local\Programs\Python\Python35\lib\os.py'>

    3 <module 'ntpath' from 'C:\Users\WCL\AppData\Local\Programs\Python\Python35\lib\ntpath.py'>

    import os.path as osp
    print(dir())
    print(osp)

    1 ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'osp']

    2 <module 'ntpath' from 'C:\Users\WCL\AppData\Local\Programs\Python\Python35\lib\ntpath.py'>

    总结:

    导入顶级模块,其名称会加入到本地名词空间中,并绑定到其模块对象。

    导入非顶级模块,只是将其顶级模块名称加入到本地名词空间中。导入的模块必须使用完全限定的名称来访问。

    如果使用了as,as后面的名称直接绑定到导入的模块对象,并将该名称加入到本地名词空间中。

    语句

    含义

    from...import..

    部分导入

    From...import...as....

    别名

    From语句:

    from pathlib import Path,PosixPath   #在当前名词空间指定导入该模块的指定成员
    print(dir())

    ['Path', 'PosixPath', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']

    from pathlib import * #在当前名词空间导入该模块所有公共成员(非下划线开头)
    print(dir())

    ['Path', 'PosixPath', 'PurePath', 'PurePosixPath', 'PureWindowsPath', 'WindowsPath', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']

    from functools import wraps as wr,partial
    print(dir())

    ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'partial', 'wr']

    from os.path import exists #加载、初始化os、os.path模块,exists加入到本地名词空间并绑定

    if exists('c:/t'):
        print('yes')
    else:
        print('no')
    print(dir())
    print(exists)

    no

    ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'exists']

    <function exists at 0x000000212F72B268>


    import os

    print(os.path.exists)
    print(exists)
    print(os.path.__dict__['exists'])
    print(getattr(os.path,'exists'))

    通过上面四种方式获得同一个对象。

    总结:

    找到from子句中指定的模块,加载并初始化他(不是导入)。

    对于import子句后面的名称。

    先查from子句导入的模块是否具有该名称的属性。

    如果不是,则尝试导入该名称的子模块。

    还没找到,则抛出importError异常

    这个名称保存到本地名词空间中,如果有as子句,则使用as子句后面的名称。

    from pathlib import Path
    print(1,Path,id(Path))

    import pathlib as p1
    print(2,dir())
    print(3,p1)
    print(4,p1.Path,id(p1.Path))

    1 <class 'pathlib.Path'> 784869820392

    2 ['Path', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'p1']

    3 <module 'pathlib' from 'C:\Users\WCL\AppData\Local\Programs\Python\Python35\lib\pathlib.py'>

    4 <class 'pathlib.Path'> 784869820392

    看出导入的Path和p1.Path是同一个对象。

    3、自定义模块

    自定义模块:.py文件就是一个模块。

    自定义模块名命名规范:

    (1)模块名就是文件名

    (2)模块名必须符合标识符的要求,是非数字开头的字母数字和下划线的组合。

    (3)不能使用系统模块名来避免冲突,除非知道模块名的用途。

    (4)模块名全为小写,下划线来分隔。

    4、模块搜索顺序

    import sys

    for i in sys.path:
        print(i)

    C:UsersWCLPycharmProjectsuntitled1packageexercise

    C:UsersWCLPycharmProjectsuntitled1

    C:UsersWCLPycharmProjectsuntitled1venvScriptspython35.zip

    C:UsersWCLAppDataLocalProgramsPythonPython35DLLs

    C:UsersWCLAppDataLocalProgramsPythonPython35lib

    C:UsersWCLAppDataLocalProgramsPythonPython35

    C:UsersWCLPycharmProjectsuntitled1venv

    C:UsersWCLPycharmProjectsuntitled1venvlibsite-packages

    C:UsersWCLPycharmProjectsuntitled1venvlibsite-packagessetuptools-28.8.0-py3.5.egg

    C:UsersWCLPycharmProjectsuntitled1venvlibsite-packagespip-9.0.1-py3.5.egg

    使用sys.pah查看搜索顺序。

    当加载一个模块的时候,需要从这些搜索路径中从前到后依次查找,并不搜索这些目录的子目录,搜索到模块就加载,搜索不到就抛出异常。

    路径可以为zip文件 egg文件、字典。

    .egg文件,由setuptools库创建的包,第三方库常见的格式,添加了元数据,版本号等,依赖项。

    信息的zip文件。

    路径顺序为:程序的主目录,程序运行的主程序脚本所在的目录,Pythonpath目录,环境变量PYTHONPATH设置额目录也是搜索模块的路径。

    标准库目录,Python自带的库模块所在目录。

    Sys.path可以被修改,追加新的目录。

    5、模块的重复导入

    模块并不会重复导入,就是查字典的过程(从前向后找。)所有加载的模块都会记录在sys.modules中,sys.modules是存储已经加载过的所有模块的字典。

    6、模块运行

    __name__        每个模块都会定义一个__name__特殊变量来存储当前模块的名称,如果不指定,则默认为源代码文件名,如果是包则有限定名。__name__这个属性,用来定义当前的文件名称。

    解释器初始化的时候,会初始化sys.modules字典,(保存已加载的模块),创建buildtins(全局函数、常量),模块,__main__、sys模块,以及模块搜索路径sys.path.

    搜索路径也要加到sys.path中来。

    python是脚本语言,任何一个脚本都可以直接执行,也可以作为模块被导入。

    当标准输入、脚本或交互式读取的时候,会将模块的 __name__,设置为__main__,模块的顶层代码就在__main__这个作用域中执行,顶层代码:模块中缩进外层的代码。

    如果是import导入的,其__name__默认就是模块名。

    从哪里运行就把__name__ 改为__main__

    7、If __name__ == ‘__        main__   ‘:用途

    1)本模块的功能测试。

    对于非主模块,测试本模块内的函数,类。

    2)避免主模块变更的副作用。

    顶层代码,没有封装,主模块使用时候没有问题,但是一旦有了新的主模块,老的主模块成了被导入模块,由于原来的代码没有封装,一并执行

    Sys.path(搜索路径)

    Sys.moduels     (字典,已加载的在里面。)

    if __name__ == '__main__':
        print('in __main__')
    else:
        print('in import module')

    in __main__

    import m2

    in import module

    8、模块的属性

    属性

    含义

    __file__

    字符串,源文件路径

    __cached__

    字符串,编译后的字节码文件路径

    __spec__

    显示模块的规范

    __name__

    模块名

    __package__

    当模块是包,同__name__:否则,可以设置为顶级模块的空字符串

    9、包

    包:特殊的模块。

    Python支持目录。

    项目中新建一个目录m

    Import m

    print(m)

    Print(type(m))

    Print(dir())#  没有__file__属性

    可以导入目录m,m也是文件,可以导入,目录模块写入代码,在其目录下简历一个特殊的文件__init__.py,在其中写入代码。

    Pycharm 中创建普通的文件夹和Python的包不同,普通包只是创建目录,后面的则是创建一个带有_init__.py文件的目录即包。

    10、子模块

    包目录下的py文件,子目录都是其子模块。

    如上建立子模块目录和文件,所有的py文件中就写一句话print(__name__)

    Import * 只是拿共有的模块的内容。公共成员,私有的不能拿。

    Import m (加载m)

    Import m.m1(加载m和m1)

    Import m.m2.m21(加载m,m2,m21)

    From m import m1 从m中加载m1

    From m.m2 import m21 三层加载。

    保留__init__文件。

    11、模块和包的总结

    包能够更好的组织模块,由其是在大的规模下代码行数很多,可以将其拆分为很多子模块,便于使用某些功能就在家相应的子模块。

    包目录中 __init__.py 是包在导入的时候就会执行,内容可以为空,也可以用于该报初始化工作的代码。

    导入子模块一定会导入父模块,导入父模块就不会加载子模块。

    包目录之间只能使用.点号作为间隔符,表示模块及其子模块之间的层级关系。       

    模块也是封装,如同类,函数,不过其能够封装变量、类、函数。

    模块就会命名空间,其内部的顶层标识符,都是其属性,可以通过__dict__或者dir()查看。

    包也是模块,但是模块不一定是包,包是特殊的模块,是一种组织方式,包含__path__属性。

    From ison import encoder:   不可以执行ison.dump

    Import json.encoder:  可以执行json.dump

    12、绝对导入和相对导入

    绝对导入:

    在import 语句或者from导入模块,模块名称前不是以.开头的,绝对导入总是去搜索模块搜索路径中找。

    相对导入:      

    包内使用相对的路径。且只能用在from语句中,不在包外用。在顶层用绝对导入。

    使用 ...上一级的上一级 ..上一级 .同一级。不在顶层使用相对导入。

    对于包来说正确的使用方式还是在顶级模块中使用这些包。

    13、访问控制

    下划线或者双下划线开头的模块能够被导入,都可以成功的导入,因为他们都是合法的标识符,都可以用作模块名。

    模块内的标识符:

    普通变量,保护变量,私有变量,特殊变量,都没有被隐藏,也就是说模块内没有私有的变量,在模块定义中不做特殊处理。

    使用from可以访问所有变量。

    14、from ... import * 和__all__

    使用from ... import *导入。起到作用的是from m import *。所有共有成员非子成员的全部导入。会影响当前的名词空间。

    定义了__all__  使用all指定导入的是哪些。

    使用__all__是一个列表,元素是字符串,每个元素都是一个模块的名称。(变量名)

    15、包和子模块

    如何访问到一个模块中的一个变量呢:

    1)直接导入整个模块  import

    2)直接导入from 模块中import 需要的属性。

    3)利用from 模块import* 利用__all__指定需要导入的名称。

    4)在__init__.py中增加from . import 模块。

    16、总结

    一、使用from xyz import *导入

    (1)如果模块没有__all__,from xyz import * 只是导入非下划线开头的模块的变量,如果是包,子模块不会导入,除非在__all__中设置,或者使用__init__.py文件中使用相对导入。

    (2)如果模块有__all__,from xyz import * 只导入__all__列表中指定的名称,哪怕是这个名词是下划线开头或者子模块。

    (3)From xyz import * 方式带入,使用简单,但是其副作用是导入大量不需要的变量,甚至造成名字的冲突,而__all__可控制被导入模块在这种导入方式下能够提供的变量名称,就是为了阻止from xyz import *导入过多的模块变量,从而避免冲突,因此,编写模块时候,尽量加入__all__

    二、From module import name1,name2导入

    导入时明确的,导入子模块,或者导入下划线开头的名称,可以有控制的导入名和其对应的对象。

    17、模块变量的修改

    模块对象是同一个,因此模块的变量也是同一个,对模块变量的修改,会影响所有者,除非万不得已,不要修改模块的变量。

    猴子补丁,也可以通过打补丁的方式,修改模块的变量,类和函数等内容。

  • 相关阅读:
    非局部均值(NL-means)
    图像对比度的理解
    汇编语言之计算器设计
    基于DnCNN模型的图像去噪论文详解(Beyond a Gaussian Denoiser: Residual Learning of Deep CNN for Image Denoising)
    P2024 [NOI2001]食物链(洛谷)
    P2256 一中校运会之百米跑(洛谷)
    P1037 产生数(洛谷)
    Java 换行和回车
    html 一些常用字符
    update
  • 原文地址:https://www.cnblogs.com/wangchunli-blogs/p/9949872.html
Copyright © 2011-2022 走看看