zoukankan      html  css  js  c++  java
  • Python之模块与包(下)

    1、什么是包

    #官网解释

    Packages are a way of structuring Python’s module namespace by using “dotted module names”

    包是一种通过使用‘.模块名’来组织python模块名称空间的方式。

    #具体的:包就是一个包含有__init__.py文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来

    #需要强调的是:

      1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错

      2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块

    2、为何要使用包

    包的本质就是一个文件夹,那么文件夹唯一的功能就是将文件组织起来

    随着功能越写越多,我们无法将所以功能都放到一个文件中,于是我们使用模块去组织功能,而随着模块越来越多,我们就需要用文件夹将模块文件组织起来,以此来提高程序的结构性和可维护性

    3、注意事项

    #1、关于包相关的导入语句也分为importfrom ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。

    例:import spam.x

    导入前:import spam.x:如果 spam 是一个模块,就会报错,spam 必须是一个包

    导入后:spam.x 直接调用模块 spam 下的 x 属性

    #2import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件

    调用包就是执行包下的__init__.py文件

    #3、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间

    4、例子

    例1:

    glance/                   #Top-level package  大包
    
    ├── __init__.py      #Initialize the glance package
    
    ├── api                  #Subpackage for api  小包
    
    │   ├── __init__.py
    
    │   ├── policy.py
    
    │   └── versions.py
    
    ├── cmd                #Subpackage for cmd 小包
    
    │   ├── __init__.py
    
    │   └── manage.py
    
    └── db                  #Subpackage for db 小包
    
        ├── __init__.py
    
        └── models.py
    目录结构
    #policy.py
    def get():
        print('from policy.py')
    
    #versions.py
    def create_resource(conf):
        print('from version.py: ',conf)
    
    #manage.py
    def main():
        print('from manage.py')
    
    #models.py
    def register_models(engine):
        print('from models.py: ',engine)
    
    包所包含的文件内容
    文件内容
    from . import api
    # 告诉调用 glance 包的模块,找api 的话从你自己的 sys.path 下 glance 下开始找 api
    glance包 __init__ 的文件内容
    # print('from api init.py')
    # __all__=['x','y','policy']   # all 方法对应 
    # x=1
    # y=2
    from . import policy
    # 告诉那个导入 api包的模块(test),找 policy 的时候,从他自己的 sys.path 开始找
    # import policy
    
    # 绝对导入
    # 告诉那个导入 api包的模块(test),找 policy 的时候,从他自己的 sys.path 下的 glance.api 开始找
    # from glance.api import policy
    
    
    # 相对导入
    # 从当前目录开始找 policy 模块
    # from . import policy
    
    # 帮 test 找到 manage 模块
    # from ..cmd import manage
    
    # 直接运行此文件会报错,
    # SystemError: Parent module '' not loaded, cannot perform relative import
    # 父模块没有被加载,不能使用相对导入的意思
    # 说明包里面的模块不应该作为单独文件直接运行
    api包 __init__ 的文件内容
    # 例1:直接 import 包方式导入模块
    # import glance.api.policy  # 导入 blance包下的api包下的policy模块
    # glance.api.policy.get()   # 执行 policy下的 get 方法
    
    # 例2:比较直观的用法
    # from glance.api import policy  # from 大包.小包 import 模块
    # policy.get()
    
    # from glance.api import policy.get  # 不能这样用,报 SyntaxError: invalid syntax 语法错误
    # get()
    
    # from glance import api.policy
    # 虽然满足点左边的是包,但是这里是 from ... import,import后面必须明确一个不能带点的东西
    
    #需要注意的是from后import导入的模块,必须是明确的一个不能带点东西,否则会有语法错误
    # 如:from a import b.c 是错误语法
    
    
    
    # api 的 init 文件
    # from glance.api import policy
    # 当导入包的时候,只会执行 api 包下面的 init 文件
    # policy.get()
    
    
    # * 的意义
    # from glance.api import *
    # 导入包,依然会执行 init 文件,但是这里的 * 不代表 api 包下所有的模块
    # * 是指 api 下 init 里面 __all__ 里面包含的属性,属性可以是任何,模块,变量等等
    # import glance.api # 导入包就执行 glance 和 api 包 init 文件
    # print(glance.api.policy)
    # 但是 policy 依然没有,因为这里只是导入包,执行 init,不会触发 all 方法
    
    
    
    # import glance.api  # 触发 api 下的 init 文件
    # print(glance.api.policy)  # ImportError: No module named 'policy'
    # init 下有 import policy
    # 先从内存里找 policy,然后从内建里找,最后从当前 test 所在的 sys.path 里找 policy 模块,找不到,报错
    
    # 让 api 包帮我找到 manage 模块
    # glance.api.manage.main()
    
    
    
    import glance
    glance.api.policy.get()
    
    
    # 如果是导入跟“包”同级的aaa包下的 glacne,就要先找到两者的父级目录,再从父级目录开始找
    import os
    import sys
    base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    print(base_dir) # 父级目录
    sys.path.append(base_dir)
    from aaa.glance.api import policy
    policy.get()
    跟 glance 同级的文件 test.py

    例2:

    if __name__=='__main__': # 表示把自己当做脚本去用
        print('ok')

    如果我们是直接执行某个.py文件的时候,该文件中那么”__name__ == '__main__'“是True,但是我们如果从另外一个.py文件通过import导入该文件的时候,这时__name__的值就是我们这个py文件的名字,而不是__main__。

    这个功能还有一个用处:调试代码的时候,在”if __name__ == '__main__'“中加入一些我们的调试代码,我们可以让外部模块调用的时候不执行我们的调试代码,但是如果我们想排查问题的时候,直接执行该模块文件,调试代码能够正常运行!

    logger.py
    def logging():
        print('ok')
    
    
    mian.py
    from core import logger
    def main():
        logger.logging()
    
    # print(__name__)
    if __name__ == '__main__':
        main()
    
    
    
    bin.py
    import os,sys
    base_dir=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # 添加ATM的绝对路径
    # print(base_dir)
    sys.path.append(base_dir)  # 把路径添加到系统环境变量里去
    
    from core import main
    main.main()
    例子

    现象:

    1、当执行 bin.py 的时候会显示 ok,正常运行,单独执行 main.py 正常显示一个 ok

    2、当 main.py 注释 if __name__ == '__main__',执行 bin.py 会显示两个 ok,单独执行 main.py 正常显示一个 ok

    3、当 main.py 只有 print(__name__),执行 bin.py 只显示 main,执行 main.py 显示 __main__

    结论:

    1:if __name__ == '__main__' 是用来调试用的,在别的地方调用该模块执行的使用不会执行被调用模块下的 if __name__ == '__main__' 下的代码

    2:在被调用模块下执行程序,会执行 if __name__ == '__main__' 下的代码,因为是自己的地方,方便调试

    5、包的2种调用方式

    clip_image001

    logger.py 文件内容

    def logger():
        print('logger')

    # from web.web2 import logger # 二层目录

    调用 logger 模块里的 logger方法

    logger.logger()

    # from web.web2.logger import logger # 调用 web包下的 web2包下的logger 模块的 logger 方法,直接用 Logger()

    直接调用 logger 模块里的 logger方法

    logger()

    .

  • 相关阅读:
    Django之数据库表的创建和ORM相关操作
    Django后续和Ajax初识
    阿里云Maven中央仓库配置
    java/javascript 时间操作工具类
    原生javascript实现文件异步上传
    MySQL中的存储函数和存储过程的简单示例
    java同步锁的正确使用
    浅谈javascript的面向对象思想
    java与javascript对cookie操作的工具类
    json字符串与json对象的相互转换
  • 原文地址:https://www.cnblogs.com/tootooman/p/9071402.html
Copyright © 2011-2022 走看看