为什么模块级别的实例只会被加载一次

模块级别的实例

# %load x.py
class MyClass:
    def __init__(self):
        print("Initializing MyClass instance")
        self.value = 42

my_instance = MyClass()

输出:Initializing MyClass instance

# file1.py
import x
import sys
print('===file1===')
print(x.my_instance.value)

# file2.py
import x
import sys
print('===file2===')
print(x.my_instance.value)

输出:
Initializing MyClass instance
=file1=
42
=file2=
42
从这个案例可以看出,file2加载x.py的时候,没有初始化,直接引用已有的实例

函数级别的实例

# %load x.py
class MyClass:
    def __init__(self):
        print("Initializing MyClass instance")
        self.value = 42


def get_instance():
    return MyClass()
# file1.py
import x

instance1 = x.get_instance()
print(instance1.value)

# file2.py
import x

instance2 = x.get_instance()
print(instance2.value)

Initializing MyClass instance
42
Initializing MyClass instance
42

结论

  • 模块级别的实例:如果你在模块中定义了一个实例,并且在多个文件中导入这个模块,那么这个实例只会被初始化一次。
  • 函数级别的实例:如果你在函数中创建实例,并在多个文件中调用这个函数,那么每次调用函数时,实例都会被重新初始化。

实现原理是什么呢

1. 模块缓存(Module Cache)

Python使用一个全局字典sys.modules来缓存已经导入的模块。这个字典的键是模块名,值是模块对象。

import sys
print(sys.modules)

当你第一次导入一个模块时,Python会检查sys.modules字典,如果模块已经存在,则直接返回缓存的模块对象;如果不存在,则执行模块的代码并将其添加到sys.modules中。

2. 模块查找路径(Module Search Path)

Python使用sys.path列表来确定模块的查找路径。当你导入一个模块时,Python会按照sys.path中的路径顺序查找模块文件。

import sys
print(sys.path)

3.模块加载(Module Loading)

当Python找到模块文件后,它会执行以下步骤:

  1. 创建模块对象:Python会创建一个新的模块对象,并将其添加到sys.modules字典中。
  2. 执行模块代码:Python会执行模块文件中的代码,初始化模块中的所有内容(包括变量、函数、类和实例)。
  3. 返回模块对象:执行完模块代码后,Python会返回模块对象,供导入语句使用。

4.后续导入(Subsequent Imports)

当同一个模块再次被导入时,Python会直接从sys.modules字典中获取已经加载的模块对象,而不会重新执行模块的代码。

具体过程
首次导入:

当你第一次导入x.py时(例如在file1.py中),Python会执行以下步骤:

  检查sys.modules字典,发现x模块不存在。
  创建一个新的模块对象,并将其添加到sys.modules字典中。
  执行x.py中的代码,初始化MyClass的实例,并将其赋值给my_instance变量。
 返回模块对象。

输出:Initializing MyClass instance。
具体过程
首次导入:

  • 当你第一次导入x.py时(例如在file1.py中),Python会执行以下步骤:

      检查sys.modules字典,发现x模块不存在。
      创建一个新的模块对象,并将其添加到sys.modules字典中。
      执行x.py中的代码,初始化MyClass的实例,并将其赋值给my_instance变量。
      返回模块对象。
    
  • 输出:Initializing MyClass instance。

后续导入:

  • 当你再次导入x.py时(例如在file2.py中),Python会执行以下步骤:

    检查sys.modules字典,发现x模块已经存在。
    直接返回缓存的模块对象,不会重新执行x.py中的代码。
    
  • 输出:42。

总结

Python通过模块缓存机制确保模块级别的实例只会被加载一次。具体步骤包括:

模块缓存:使用sys.modules字典缓存已经导入的模块。
模块查找路径:使用sys.path列表确定模块的查找路径。
模块加载:首次导入时,创建模块对象并执行模块代码。
后续导入:直接返回缓存的模块对象,不会重新执行模块代码。

这种机制确保了模块级别的实例在内存中是唯一的,避免了重复初始化和资源浪费。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值