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、模块变量的修改

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

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

  • 相关阅读:
    POJ 2236 Wireless Network(并查集)
    POJ 2010 Moo University
    POJ 3614 Sunscreen(贪心,区间单点匹配)
    POJ 2184 Cow Exhibition(背包)
    POJ 1631 Bridging signals(LIS的等价表述)
    POJ 3181 Dollar Dayz(递推,两个long long)
    POJ 3046 Ant Counting(递推,和号优化)
    POJ 3280 Cheapest Palindrome(区间dp)
    POJ 3616 Milking Time(dp)
    POJ 2385 Apple Catching(01背包)
  • 原文地址:https://www.cnblogs.com/wangchunli-blogs/p/9949872.html
Copyright © 2011-2022 走看看