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_workspace\Felix_test\test_init\my_init),通过绝对地址加入

# main_test.py

import
sys,os sys.path.append(os.path.abspath(r'D:\Python_workspace\Felix_test\test_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_workspace\Felix_test\test_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

posted on 2020-05-04 19:46  落日峡谷  阅读(5069)  评论(0编辑  收藏  举报

导航