【无标题】


前言

在使用fairseq进行model的注册时,发现对python文件中的 __init__.py 文件的原理不清晰,导致注册失败。在这里记录一下。


一、__init__.py 是什么?

__init__.py 文件是Python包(或目录)中的特殊文件,用于标识包目录,并在包被导入时执行初始化操作。它可以包含包级别的变量、函数和类,也可以用于指定包的子模块或子包。

当导入一个包时,init.py 文件会在包的初始化过程中执行。在其中可以执行任何必要的初始化操作,例如设置包的全局变量,导入子模块,或者执行其他自定义操作。这使得包的组织和初始化更加方便。

比如:以下目录结构中

my_package/
|_ __init__.py
|_ module1.py
|_ module2.py

__init__.py可以是以下内容:

# my_package/__init__.py

print("Initializing my_package...")

# 导入子模块
from . import module1
from . import module2

# 定义包级别的变量
package_variable = "This is a package variable"

当导入 my_package 时,__init__.py 文件中的代码将被执行:

import my_package

输出 “Initializing my_package…” 并使 my_package 可用于导入包中的子模块和访问包级别的变量。

__init__.py 文件可以为空,但通常会包含有用的初始化代码。这对于组织代码、设置包的默认配置以及执行导入操作非常有用。

二、模块、包和命名空间

在使用__init__.py之前,有必要理解什么是module、package、namespace。

1.module(模块)

模块是包含Python代码的单个文件。文件的名称通常与模块的名称相同,但具有 .py 扩展名。模块可以包含变量函数以及可执行的代码

其他Python程序可以使用 import 语句导入模块,以便重用其中定义的功能。
例如,名为 my_module.py 的模块包含了一个函数 my_function,那么其他程序可以使用以下方式导入并调用该函数:

import my_module
my_module.my_function()

在模块内部,通过全局变量 __name__ 可以获取模块名(即字符串)
python my_module.py <arguments>
这项操作将执行模块里的代码,和导入模块一样,但会把 __name__ 赋值为 “__main__”。 如果脚本是被直接执行的,即作为主程序运行,那么 __name__ 的值将被设置为 “__main__”。
如果脚本是被导入为模块的,那么 __name__ 的值将被设置为脚本的文件名(不带扩展名)。

__pycache__

Python 把模块的编译版缓存在 pycache 目录中,文件名为 module.version.pyc,version对编译文件格式进行编码,一般是 Python 的版本号。
Python在两种情况下不检查缓存。其一,从命令行直接载入模块,只重新编译,不存储编译结果;其二,没有源模块,就不会检查缓存。为了支持无源文件(仅编译)发行版本,编译模块必须在源目录下,并且绝不能有源模块。
——“没有源模块,就不会检查缓存”:当Python导入一个模块时,它通常会检查是否存在已编译的字节码缓存文件(以 .pyc 或 .pyo 为扩展名)。如果有源模块(.py 文件),Python会比较源模块的时间戳和编译后的字节码文件,以确定是否需要重新编译。但如果没有源模块,只有已编译的字节码文件存在,Python将跳过这个检查。
——“为了支持无源文件(仅编译)发行版本,编译模块必须在源目录下,并且绝不能有源模块”:即如果发布一个不包含源代码的Python发行版,只包含已编译的字节码文件,那么这些字节码文件必须位于源代码的目录下。并且,如果发布版本不包含源代码(即 .py 文件),那么你应该确保没有源模块存在,以防止Python尝试重新编译。

2.Package(包)

是一个包含多个模块的目录,通常包含一个名为 __init__.py 的特殊文件。包可以嵌套,形成包的层次结构,以便更好地组织和管理模块。
使用包的主要目的是避免模块名称冲突,使代码更模块化。
例如,名为 my_package 的包,包含两个模块 module1 和 module2,其他程序可以这样导入其中的模块:

from my_package import module1
from my_package import module2

包是一种用“点式模块名”构造 Python 模块命名空间的方法。例如,模块名 A.B 表示包 A 中名为 B 的子模块。正如模块可以区分不同模块之间的全局变量名称一样,点式模块名可以区分 NumPy 或 Pillow 等不同多模块包之间的模块名称。

两种导入子模块方式:

  • 使用 from package import item 时,item 可以是包的子模块(或子包),也可以是包中定义的函数、类或变量等其他名称。import 语句首先测试包中是否定义了 item;如果未在包中定义,则假定 item 是模块,并尝试加载。如果找不到 item,则触发 ImportError 异常。
  • 使用 import item.subitem.subsubitem 句法时,除最后一项外,每个 item 都必须是包;最后一项可以是模块或包,但不能是上一项中定义的类、函数或变量。

包中含有多个子包时:

Python 程序的主模块必须始终使用绝对导入,如from sound.effects import echo而非 from .. import echo

3.Namespace(命名空间)

命名空间变量名对象之间的映射,用于解析变量名引用
Python中存在多个命名空间,包括全局命名空间global namespace)和局部命名空间local namespace)。
当引用一个变量时,Python首先在局部命名空间中查找,然后在全局命名空间中查找,以确定变量的值。
如:

x = 1  # 在全局命名空间中定义变量
def my_function():
    x = 2  # 在局部命名空间中定义变量
    print(x)  # 首先查找局部命名空间,然后在全局命名空间找到变量 x
print(x)
my_function()
#output:1
#       2

三、__init.py__的用途

博客


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值