ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

[python][转载]__init__.py使用

2021-12-29 11:02:00  阅读:176  来源: 互联网

标签:__ py python __. init import C1


本文文章源自:__init__.py和__main__.py文件使用心得 - 知乎

在构建大型Python项目时经常会使用到__init__.py和__main__.py文件,通过它们可以灵活的管理模块和包。

1 __init__.py文件的应用

在Python项目中,如果某个文件夹被设置成包的形式,那么该文件夹中必须要包含一个__init__.py文件,即使它是空文件。当导入这个包时,__init__.py文件中的代码会被优先执行。

  • 构建层级包

封装一个包,确保每个目录下都定义了一个__init__.py文件, 例如:

ml_api/
    __init__.py
    regression/
        __init__.py
        linear_regression.py
        ridge_regression.py
        ...
    classification/
        __init__.py
        svm.py
        xgboost.py
        ...
run.py

这样就能够在其他项目模块执行各种import语句,如下所示:

import ml_api.classification.svm
from ml_api.classification import xgboost
import ml_api.regression import ridge_regression as ridge

__init__.py文件的目的是使得不同运行级别的包能够可选的初始化代码。如果执行了语句import ml_api那么文件ml_api/__init__.py将被导入,建立以ml_api为命名空间的内容。像import ml_api.classification.svm这样导入,那么文件ml_api/__init__.py和文件ml_api/classification/__init__.py将在文件ml_api/classification/svm.py导入之前导入。

  • 控制子模块导入

绝大部分时候让__init__.py文件为空就好,但是有些情况下可以包含代码,从而行使特殊的功能,如控制子模块导入。

# ml_api/classification/__init__.py
from . import svm
from . import xgboost

现在仅通过import ml_api.classification一行代码就可以替代import ml_api.classification.svmimport ml_api.classification.xgboost 两行代码的功能。

  • 对子模块进行重构

__init__.py还可以将多个模块合并到一个逻辑命名空间。程序模块可以通过变成包的形式分割成多个独立的文件,不妨考虑

# test_module.py
class C1:
    def f1(self):
        print("C1.f1")

class C2(C1):
    def f2(self):
        print("C2.f2")

如果想把test_module.py拆分成两个文件,然后分别定义成类,从而实现逻辑上独立。要做到这一点,首先需要使用test_module目录来替换文件test_module.py。 这这个目录下,创建如下文件:

test_module/
    __init__.py
    c1.py
    c2.py

在c1.py文件中插入以下代码:

# c1.py
class C1:
    def f1(self):
        print("C1.f1")

在c2.py文件中插入以下代码:

# c2.py
from .c1 import C1
class C2(C1):
    def f2(self):
        print("C2.f2")

最后,在 __init__.py 中,将上述两个文件聚合在一起:

# __init__.py
from .c1 import C1
from .c2 import C2

至此,test_module就整合为统一的逻辑模块

>>>import test_module
>>>c1 = test_module.C1()
>>>c1.f1()
C1.f1
>>>c2 = test_module.C2()
>>>c2.f2()
C2.f2

上面讨论的其实是包的设计问题,在一个大型的代码库中,每个功能模块都是独立的文件,用户如果想使用相应的功能按需导入即可

from package.module_1 import C1
from package.module_2 import C2
...

但是这样往往会导致用户的负担增加,因为他需要知道不同的功能代码位于包的哪个模块,通常情况下应该是将这些逻辑统一起来,使用一条import语句简化导入流程

from package import C1, C2

因此需要使用__init__.py文件来将每个独立的模块聚合在一起。再举一个亲身使用的例子,假设使用fastAPI作为后端搭建机器学习算法API,为了叙述方便,简化的目录结构如下

ml_api/
    ml/
        __init__.py
            regression.py
            classification.py
    run.py

构建回归算法的请求API

# regression.py
from fastapi import APIRouter
...
regression_app = APIRouter()
...

构建分类算法的请求API

# classification.py
from fastapi import APIRouter
...
classification_app = APIRouter()
...

使用__init__.py文件整合所有算法模块

# __init__.py
from .regression import regression_app
from .classification import classification_app

最后在run.py文件中统一所有的路由,组建完整的API

import uvicorn
from fastapi import FastAPI
...
from ml import regression_app, classification_app

app = FastAPI(...)
...
app.include_router(regression_app, prefix='/regression')
app.include_router(classification_app, prefix='/classification')

if __name__ == '__main__':
    uvicorn.run('run:app', host='0.0.0.0', port=55555, reload=True, debug=True)
  • 延迟加载

对于构建一个很大的包,如果在__init__.py文件中一次性导入了所有必需的模块,可能会引发一些问题。所以在某些特殊情况下,需要设计成当组件使用时才会被加载。以上一小节第一个项目为例,如果要实现这种逻辑,__init__.py文件需要改动一些代码:

# __init__.py
def C1:
    from .c1 import C1
    return C1()

def C2():
    from .c2 import C2
    return C2()

在这个版本中,只有当C1和C2函数被调用时才会加载C1和C2类,但是对于用户而言,使用方法上并不会有什么不同

>>>import test_module
>>>c1 = test_module.C1()
>>>c1.f1()
C1.f1

2 __main__.py文件的应用

在Python项目中,__main__.py相较于__init__.py文件的用法来说比较单一,一句话总结就是,如果想要使得某个文件夹能够执行,那么该文件夹中必须要包含一个__main__.py文件,否则就会抛出异常。假设项目目录结构如下

your_package/
    __init__.py
    __main__.py
    a.py
    b.py
    ...

然后在__main__.py文件中插入行使相关功能的代码,运行your_package即可

>>>python your_package

标签:__,py,python,__.,init,import,C1
来源: https://blog.csdn.net/FL1623863129/article/details/122210888

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有