• Python:__init__.py文件和、__all__、import、__name__、__doc__


    有时候,很容易忽略一些看上去不起眼的小细节,可能人总是有那么点理所当然的想法。

    就像init.py文件,是不是感觉像个熟悉的陌生人?~~~

    这里来浅析一下一些基础概念(都是左右各双下划线)。

    1. __init__.py 文件:这个文件,就像一个标识符一样,用来表明一个文件夹是python包还是一般文件夹,如果文件夹中存在该文件,就是python包;可以试试pycharm直接建立package,就会发现刚建完就已经存在__init__.py文件了。

    这个文件用处:

    用处一:当用于import对象时,可以识别出哪些是可以导入的包,哪些只是一般文件夹;

    用处二:可以在其中导入需要的对象,然后通过在执行程序中import package来引用这些包,所以简化了执行程序,因为每次导入package的时候会自动执行__init__.py;但最好不要在这里写自己的模块,该文件越简单越好;

    用处三:__all__参数,只用于指定 from package import * 时,导入的包是哪些,不需要的包可以先不导入;并不影响from package import module/package、import package.module等形式的导入。

    注意:该文件可以为空,即不做操作,但是package必须要有这个文件。

    2. import:用于导入包、函数、变量、类等;那么import干了些啥?(sys.path是可以修改的,且从package包导入模块需要用 from package import ... 形式

    3. __name__:用于判断当前模块是不是主程序文件(主执行),也就是查看 __name__ 的值是否为 '__main__' ,如果则该程序属于主程序文件,如果不是则显示该文件的文件名;

    4. __doc__:模块的注释文本,例如函数或者类的说明,用 '''...''' 三引号形式包围;

    5. 示例说明

    (1)首先文件夹和文件如下:可见my_init是一个python包,package_test也是一个包,my_init_2是一个普通文件夹。

    (2)首先两个 __init__.py都为空,此时import模块的操作如下:

    ## import_test.py 内容
    
    class BBB():
        def __init__(self, kk):
            self.kk = kk
            print(self.kk)
        
        def gogogo(self):
            print('---test class with import---')
            
    def ss_B():
        print('---------------- this is the imported *.py file --------------')
    
    def tt_B():
        print('this is also from imported file')
    
    print('it is very bad')
    print(__name__)
    
    if __name__ == "__main__":
        print(__name__)
        ss_B()
    • main_test.py导入import_test模块 —— 两个py文件在同一目录下
    # 直接导入,main_test.py
    
    import import_test as it
    it.ss_B()
    print(__name__)

    很明显,前两个结果来自导入import_test时,自动执行了该模块 import_test中的内容(输出的结果1和结果2);而为啥没继续执行下面的 if __name__='__main__' 里面的内容,那是因为此时__name__的值为:import_test(输出的结果2),并不是__main__,所以不会执行。

    然后,结果3调用了import_test模块内的函数,结果4返回__main__,表明当前模块(main_test.py)属于主程序。

    • main_test.py导入import_test模块,同一目录,也可以如下
    # main_test.py

    from
    import_test import ss_B #可以直接通过py文件导入函数,模块可以通过 from module_name import func 或者直接 import module_name;但是package要通过from package_name import module_name 或者 import package_name.module_name def ss(): print('---------------- this is the main *.py file --------------') if __name__ == "__main__": print(__name__) #用于判断主程序是当前程序还是其他程序 ss() ss_B()

    此时不能用:from my_init import import_test,为什么呢?因为my_init这个文件不在搜索路径下,但是它的子目录在搜索路径(D:\Python_workspace\Felix_test\test_init\my_init)下,可以使用sys.path查看:

    如果要是用,需要先将该目录加入搜索路径(它本身的目录为 —— D:Python_workspaceFelix_test est_initmy_init),通过绝对地址加入

    # main_test.py

    import
    sys,os sys.path.append(os.path.abspath(r'D:Python_workspaceFelix_test est_init')) #只有test_init目录下才包含my_init目录 from my_init import import_test

     

    • main_test.py导入package_test包中的模块,main_test和package_test包同一目录
    # sub_test.py 内容
    
    def sub_packege_test():
        '''testing on the sub_packege_test doc ---'''
        print('it is a sub-package!')

    则,调用时,__doc__表示说明文本(每个对象,例如函数、类、模块都有这个属性):

    # main_test.py
    
    from package_test import sub_test     #导入包中的文件
    sub_test.sub_packege_test()
    print(sub_test.sub_packege_test.__doc__)  #该函数说明

    也可:

    from package_test.sub_test import sub_packege_test  #导入包内*.py文件中的函数
    sub_packege_test()
    • my_init_2文件夹中的test_1.py可以直接调用test_2.py,同一目录,虽然这个文件夹不是package
    # test_2.py 内容
    def xx():
        print('-----what happended here-----')
    print(xx())  
    
    # ---------------------------------------------------------------------------
    # test_1.py 内容 import test_2 as t2 t2.xx() print('it is test_1.py')
    • my_init_2文件夹中的test_2,无法直接import my_init包中的import_test.py模块,需要先添加搜索路径;反之,也可以在my_init包中的模块,import另一个文件夹(my_init_2)中的模块 —— 注意:这可能会失败,因为你import的模块有可能会导入import其他的包,但是这些其他包又不在搜索路径中时,就会报错。
    # test_2.py 内容
    
    import os
    import sys
    sys.path.append(os.path.abspath(r'D:Python_workspaceFelix_test	est_init'))  #绝对路径导入包,先将文件夹加入搜索路径,然后导入;相对路径个人感觉不太好用
    from my_init import import_test
    
    import_test.ss_B()
    
    def xx():
        print('-----what happended here-----')
    print(xx())  

    所以,最好不要嵌套太多层来进行import。。。

    (3)使用__init__.py方法

    • main_test.py中import package_test中的模块

    首先,修改my_init包的package_test中的__init__.py文件如下(使用__all__变量):

    __all__ = ['sub_test']   #可以只选部分,不用导入过多包,只会影响 from package_test import * 中的导入结果
    
    print('this is from __init__ file, sub-package')

    然后,import使用:

    # sub_test.py 内容
    def sub_packege_test():
        '''testing on the sub_packege_test doc ---'''
        print('it is a sub-package!')
    
    #-------------------------------------------------
    # main_test.py
    from package_test import *
    sub_test.sub_packege_test()
    print(__name__)
    sub_test_2.sub_packege_test_2()

    可见:当使用 from package_test import * 时,读取到的包均属于package_test的 __init__.py中 __all__变量的值,不在该变量值中的包不会读取。

    • 此时,如果__init__.py中没有某个模块,而你又要使用时,可以在执行文件中自己导入
    # main_test.py

    from
    package_test import sub_test_2 # 这种形式的导入与__init.py中的__all__参数无关 sub_test_2.sub_packege_test_2()

    • 如果,不使用__all__变量,直接在__init__.py中import需要的包
    # package_test中的__init__.py文件内容:
    
    from package_test import sub_test
    print('this is from __init__ file, sub-package')

    这种情况与直接在需要的地方通过from package import module,来导入模块差不多;只不过如果使用了__init__.py文件,那么就会执行一次__init__.py文件,将所有需要的包一次性导入,在执行文件中就不需要写很多import语句,而只需要导入包package即可,然后通过包来引用模块;同时此时如果该文件里面还有其他代码也会执行。

    # main_test.py
    
    from package_test import sub_test    #这种形式,如果有很多包则会比较麻烦
    #import sub_test   #直接导入该模块不行
    sub_test.sub_packege_test()
    
    
    # 所以可以这样,通过package包来引用,如果在__init__.py中写了很多个from package import module,则都可以这样使用;也就是简化了很多import语句
    # main_test.py
    import package_test package_test.sub_test.sub_packege_test()

    注意:

    1. from module/package import func/module:只是将某模块或者package的一部分导入当前命名空间;

    2. import语句中,如果导入的是模块则会执行该模块代码;如果是package,则会执行package包的__init__.py文件;

    3. sys.modules 和 sys.path的官方链接、解释:

    4. __init__.py文件越简单越好,也可以为空。

    5. __init__.py的import操作,主要是可以简化执行程序中的import语句;而__all__只用于控制from package import * 中导入的包。

    6. 以上都是用的绝对导入import;其中相对导入和绝对导入

    #

    参考:

    https://blog.csdn.net/fitzzhang/article/details/78988155

    https://www.jianshu.com/p/dacbed54d063

    https://www.runoob.com/python/python-modules.html

    https://blog.csdn.net/weixin_38256474/article/details/81228492

    https://www.cnblogs.com/byronsh/p/10745292.html

  • 相关阅读:
    未能加载文件或程序集“xxx, Version=x.x.x.x, Culture=neutral, PublicKeyToken=xxxxxxxxxxxx”或它的某一个依赖项。系统找不到指定的文件
    RabbitMQ本地正常,发布到服务器上 出行连接失败
    Windows 服务 创建 安装 卸载 和调试
    CSS 格式化 一行一条
    ES6---new Promise()讲解,Promise对象是用来干嘛的?
    Win Server 2008 R2 IIS 默认只能添加一个 443 HTTPS 端口
    MVC 部分视图:Partial() 、RenderPartial() 、 Action() 、RenderAction() 、 RenderPage() 区别
    ;(function ($, undefined){ })(jQuery); 的使用及说明
    JS中的call()方法和apply()方法用法总结
    MongoDB服务无法启动,windows提示发生服务特定错误:100
  • 原文地址:https://www.cnblogs.com/qi-yuan-008/p/12827918.html
Copyright © 2020-2023  润新知