zoukankan      html  css  js  c++  java
  • [TimLinux] Python 模块

    1. 概念

     模块是最高级别的程序组织单元,它将程序文件和数据封装起来以便重用。实际上,模块往往对应Python文件,每一个文件都是一个模块,并且模块导入其他模块之后就可以使用导入模块定义的变量,模块和类实际上就是一个重要的命名空间。

    2. 模块的导入

    • import:使导入者以一个整体获取一个模块,import b可能对应的文件:b.py, b.pyc, b.pyo, 模块包b目录,b.so/b.dll, Python内置库,b.zip文件组件(导入时自动给解压缩),内存内映射(frozen的可执行文件)。
    • from:允许导入者从一个模块文件中获取特定的变量名。
    • imp.reload:在不中止Python程序的情况下,提供了一种重新载入模块文件代码的方法。

    import和from是赋值语句:import将整个模块对象赋值给一个变量名,from将一个或多个变量名赋值给另一个模块中同名的对象,from复制的变量名会变成对共享对象的引用。

    small.py:

      x = 1

      y = [1,2]

    from small import x,y # 从small里面拷贝两个名字

    x = 42 # 改变我的x值

    y[0] = 42  # 这是修改了一个对象,而不是变量名

    import small

    print(small.x) # 仍然为值1,获取small模块中的x,不是我的x

    print(small.y) # [42, 2], y[0]被修改为42了。

    from module import name1, name2概念上与下面的代码一样。

    import module

    name1 = module.name1

    name2 = module.name2

    del module

    3. 模块的作用

    • 代码重用:模块文件中的代码是永久的,可任意多次重新载入、运行。
    • 系统命名空间的划分:模块是Python总最高级别的程序组织单元。
    • 实现共享服务和数据:全局对象数据统一定义,多个代码文件间实现共享。

    4. import工作原理

    导入(import)是运行时的运算,程序第一次导入指定文件时,执行三个步骤:

    • 查找:找到模块文件。程序所在目录,PYTHONPATH, 标准链接库目录,任何.pth文件的内容(sites-packages)(这是个内容构成:sys.path列表)
    • 编译:文件编译成位码(需要时):.pyc, .pyo文件
    • 执行:执行模块的代码来创建所定义的对象

    以上操作,只有在第一次导入文件才需要,以后的导入操作则直接读取内存中的数据,导入的模块存放在sys.modules中.

     5. 模块包

    $ mkdir packages/sound/{effects,filters,utils} -p
    $ cd packages/
    
    1. 存在sound/__init__.py文件
    $ python
    >>> from sound import *  # 没有报错,此时没有__init__.py文件
    >>> dir()
    ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__'] # 显示的列表中没有该sound包相关的信息
    
    $ cat > sound/__init__.py
    print("in sound.__init__.py")
    __all__ = ['effects','filters','utils']
    $ python
    >>> from sound import *
    in sound.__init__.py
    >>> dir()
    [..., 'effects', 'filters', 'utils'] # 多出了__all__里面配置的变量
    >>> dir(effects) # 注意effects没有加引号,也就是可以直接通过effects访问,effects下当前没有__init__.py文件
    
    2. 存在sound/__init__.py, test1.py文件
    $ cat > sound/test1.py
    print("in sound.test1.py")
    
    def test():
        print("in sound.test1.py:test()")
    $ python
    >>> from sound import *  # 导入所有,但是不存在test1
    in sound.__init__.py
    >>> test1.test()
    >>> dir(test1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'test1' is not defined
    
    原因:test1 没有加入到 __all__中
    $ cat > sound/__init__.py
    print("in sound.__init__.py")
    __all__ = ['effects','filters','utils','test1'] # 加入test1
    $ python
    >>> from sound import *  # 导入所有,包含test1
    in sound.__init__.py
    >>> test1.test()
    >>> dir(test1)
    
    $ cat > sound/__init__.py  # 恢复到不含有test1
    print("in sound.__init__.py")
    __all__ = ['effects','filters','utils'] # 不含有test1
    $ python
    >>> import sound.test1  # 单独导入test1
    in sound.__init__.py
    in sound.test1.py
    >>> dir()
    [..., 'sound'] # 全局有sound
    >>> dir(sound)
    [..., 'test1'] # sound内有test1,但是没有effects等定义在__all__中的模块
    >>> sound.test1.test() # 可以访问
    in sound.test1.py:test()
    
    $ python
    >>> from sound import test1
    in sound.__init__.py
    in sound.test1.py
    >>> dir()
    [..., 'test1'] # 有test1,不需要在__all__定义,访问了sound/__init__.py文件,没有sound
    >>> dir(sound) # 出错
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'sound' is not defined
    
    >>> test1.test() # 可以访问
    in sound.test1.py:test()
    
    $ python
    >>> import sound # 无法访问test1
    in sound.__init__.py
    >>> dir()
    [..., 'sound']
    >>> dir(sound) # 没有test1, 没有effects(定义在__all__变量中)
    >>> sound.test1.test() # 不可以访问
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'sound.test1' is not defined
    
    $ cat > sound/__init__.py
    print("in sound.__init__.py")
    __all__ = ['effects','filters','utils']
    from . import test1
    >>> import sound # 可以访问test1
    in sound.__init__.py
    in sound.test1.py
    >>> dir()
    [..., 'sound'] # 有sound
    >>> dir(sound)
    [..., 'test1'] # 有test,没有effects(定义在__all__变量中)
    >>> sound.test1.test() # 可以访问
    in sound.test1.py:test()
    View Code

    总结:
    1. import sound:

      执行sound/__init__.py,并且解析__all__变量(如果存在的元素不存在,会抛出AttributeError异常)
      a) 可以访问sound.* (*必须是在__init__.py中有定义的变量,或者通过from 语句导入的模块)
        from . import test1: 可以访问sound.test1
        import test1: 此时或提示无法导入模块(sys.path找不到test1.py文件)
      b) 不会展开__all__变量,即无法访问sound.effects(effects内是否存在__init__.py,效果一致)
    2. from sound import *:
      a) 执行sound/__init__.py,并且解析__all__变量(如果存在的元素不存在,会抛出AttributeError异常)
      b) 展开__all__:可以访问effects.xxx
    3. from sound import test1:

      执行sound/__init__.py,执行sound/test1.py,不需要在sound/__init__.py文件中做任何配置,即可访问到sound.test1.py (只需要sound/__init__.py文件存在)

    扩展解释:

    sound/
        __init__.py
        test1.py (test()) # e_test1.py要访问该方法,在e_test1.py文件中需要明确import该模块
        effects/
            __init__.py
            e_test1.py (e_test()) # 要访问test1.py提供的方法,需要明确的import test1模块

    from sound import effects.e_test1:错误,语法不支持(import后不能带.)
    from sound.effects import e_test1:

    •  依次调用:sound/__init__.py (不展开__all__) -> sound/effects/__init__.py(不展开__all__) -> sound/effects/e_test1.py
    •  然后将e_test1 = """e_test1.py中的全部Python代码"""
    •  如果sound/__ini__.py内有from . import test1.py #test1.py提供的test方法,e_test1.py内还是无法访问的,需要在e_test1.py文件内单独import(但是在真实执行时,在解析sound/__init__.py文件的时候已经解析过了,不会再次解析。
  • 相关阅读:
    负载均衡服务之HAProxy基础入门
    WEB缓存系统之varnish代理以及健康状态检测配置
    WEB缓存系统之varnish缓存项修剪
    WEB缓存系统之varnish状态引擎
    WEB缓存系统之varnish基础入门
    WEB缓存控制机制与varnish简介
    WEB应用之httpd基础入门(五)
    Appium移动端测试--基础预热
    postman接口测试-参数化-测试数据Text文本
    机器学习环境搭建安装TensorFlow1.13.1+Anaconda3.5.3+Python3.7.1+Win10
  • 原文地址:https://www.cnblogs.com/timlinux/p/9096724.html
Copyright © 2011-2022 走看看