zoukankan      html  css  js  c++  java
  • Python 模块化 from .. import 语句介绍 (二)


    from语句


    例一、

    from pathlib import Path,PosixPath
    
    print(dir())
    print(Path)
    print(PosixPath)
    
    运行结果:
    ['Path', 'PosixPath',...]
    <class 'pathlib.Path'>
    <class 'pathlib.PosixPath'>
    

      Path和PosixPath是pathlib模块中定义的类,使用 "from .. import .."语句可以直接映射pathlib模块中的资源在当前的命名空间。接下来就可以使用资源名直接调用,不需要再以"pathlib.Path" 这样的完整资源层次关系调用。

    例二、

    from pathlib import Path,PosixPath
    import pathlib.Path
    
    print(dir())
    print(Path)
    print(PosixPath)
    print(pathlib.Path)
    
    运行结果:
    Traceback (most recent call last):
    File "C:/python/1207.py", line 2, in <module>
    import pathlib.Path
    ImportError: No module named 'pathlib.Path'; 'pathlib' is not a package
    

      

    包的简单概念:
    包必须是目录,且此目录下有一个__init__.py,比如下面的层级关系:

    |--包

       |--__init__.py
       |--子模块.py
       |--子模块
          |--子模块.py


    包下面可以有多个嵌套的子模块,后面会单独一篇文章介绍包。


    模块必须是一个文件夹或者单独的以py结尾的文件,比如下面的层级关系:
    |--os
       |--path.py

    上面的树状文件路径中os是一个顶级模块,path是os模块下的一个子模块。


    再看下pathlib的层级关系:
    |--pathlib.py
       |--class Path(PurePath)
    上面的pathlib就是一个单独的顶级模块,Path只是这个模块中的一个类,并不是一个模块,所以import pathlib.Path 直接导入时会抛出 No module named 'pathlib.Path' 异常。


    如果需要直接导入模块里面的资源就必须使用 from 模块 import 资源名 的格式,下一个例子就会介绍这种格式。

    例三、

    from pathlib import * #导入模块下的所有"公共"资源
    
    print(dir())
    print(Path.cwd())
    运行结果:
    ['Path', 'PosixPath', 'PurePath', 'PurePosixPath', 'PureWindowsPath', 'WindowsPath', ...]
    

      

    通过前一个例子的异常,我们知道import 无法直接导入顶级模块或子模块中的资源(类,方法,属性),使用 from .. import * 语句(第一种方法)就会将指定模块下的所有资源导入,或者指定资源名的格式导入部分资源: from .. import 资源(第二种方法) ,这两种方法都会将资源同名映射到当前命名空间。
    第二种方法相比第一种方法的好处是,只导入需要的资源,其它用不到的资源通通不导入,可以节省内存,这是一种好的编程习惯,在程序效率上任何微小的提升积累起来都是大的提升。

    本例子中特别强调了 from .. import * 导入的是模块下的所有”公共“资源,公共资源也就是不以单下划线(_xx)或者双下划线(__yy__)开头的资源。

    例四、

    from os import path as osp #别名
    print(dir())
    
    运行结果:
    ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'osp']
    

      在导入子模块或者资源时也可以使用as 语句重命名子,当前命名空间最终保存的就是重命名后的映射。


    例五、

    from os.path import exists
    
    print(dir())
    if exists('c:/windows'):
    print('found')
    else:
    print('not found')
    
    运行结果:
    ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'exists']
    found
    

      当前例子中使用了 from 包.模块 import 子模块 的格式,说明from语句后的模块可以是完整层级关系下的模块(依然有一个找模块、加载模块、初始化模块的过程),也可以是单独的模块,最终当前加入命名空间的依然是子模块名的映射。

    例六、

    from os.path import exists
    
    print(dir())
    print(exists)
    
    import os
    print(dir())
    print(os.path.exists)
    print(os.path.__dict__['exists'])
    
    运行结果:
    ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'exists']
    <function exists at 0x000001F7AEDAC268>
    ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'exists', 'os']
    <function exists at 0x000001F7AEDAC268>
    <function exists at 0x000001F7AEDAC268>
    

      

    当前例子中先后使用不同的导入方式,导入path模块的exists函数,最终比较内存地址时,按道理说前后调用的方式是不一样的,却发现内存地址是一致的。
    模块加载机制中可能有一种在当前环境中防止重复导入模块的机制,下一篇文章再做介绍。


    总结:

    1. from 语句需要指定模块,模块可以是单独的顶级模块,也可以是层级关系下的子模块,加载并初始化该模块

    2. import 语句后指定的是该模块的资源(类,方法,函数),或者导入该模块下的子模块。

         先查找导入的模块是具有该名称的属性 -->如果没有,就尝试导入为该名称的子模块 --> 如果还没有找到,就抛出ImportError异常。下一篇文章也会举例介绍该模块搜索顺序。

         如果该名称后有as语句,则关联as语句后的名称到当前名词空间

  • 相关阅读:
    [Windows]Windows的访问控制模型
    [C/C++]宽字符与控制台程序
    [SQL Server]自动化附加和分离数据库
    [ASP.NET]自动发送邮件功能的实现
    [Windows]Windows路径探究
    asp.net中怎么样获取前一页地址
    CheckBox全选CheckBoxList
    远程SQL插入数据
    SQL存储过程调用作业的方法
    [转]javascript 调用后台函数
  • 原文地址:https://www.cnblogs.com/i-honey/p/8031218.html
Copyright © 2011-2022 走看看