You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python不同路径导入同一对象:类属性与原生类型行为差异

Python导入差异的底层原因

核心前提:Python模块的加载规则

Python靠sys.modules字典缓存已加载的模块,模块的唯一标识是它的完全限定名(比如Folder.shared)。如果两次导入的路径导致模块的完全限定名不一样,Python会把它当成两个完全独立的模块,加载两次,生成两个互不关联的模块实例——对应的类、变量也都是各自独立的对象。


现象1:类属性Shared.i的差异解析

当IMPORT_VIA_PATH=False时

这种情况下,main.py和setter.py用了不同的导入路径,导致shared模块的完全限定名不一致:

  • 比如main.py把Folder目录加到sys.path,直接import shared,此时模块的名字是shared;
  • 而setter.py用from Folder import shared导入,模块的名字是Folder.shared。

这两个模块会被存在sys.modules的不同键下,是完全独立的实例。所以main里的Shared类和setter里的Shared类是两个不同的类对象,各自的类属性i也分属不同的内存空间。当setter修改自己的Shared.i时,完全不会影响main里的Shared.i,两者的内存地址自然不同(你看到main输出i=2,说明main里的类属性没被setter修改)。

当IMPORT_VIA_PATH=True时

main和setter用了相同的导入路径(比如都是from Folder import shared),模块的完全限定名都是Folder.shared,Python只会加载一次这个模块。此时main和setter里的Shared类是同一个对象,类属性i共享同一块内存,所以setter修改后,main读取到的就是修改后的值0,内存地址也完全相同。


现象2:模块级原生变量i无差异的原因

这里的关键是Python的小整数缓存机制:Python会预先缓存-5到256之间的整数对象,所有引用这些值的变量都会指向同一个内存地址。

当你把类属性换成模块级变量i时:

  • 如果模块被加载两次,两个模块里的i初始值都是同一个缓存的整数(比如初始值是0),所以内存地址自然相同;
  • 即使你修改其中一个模块的i,只要修改后的值还在小整数缓存范围内,不同模块里的同值整数也会共享地址。而你观察到无论IMPORT_VIA_PATH取值如何,i始终为0且地址相同,大概率是因为两次导入的模块里,i的初始值都是0,且没有被修改(或者修改后的值也在缓存范围内)。

补充:如果模块级变量是可变类型(比如列表),你会发现和类属性的表现一致——不同模块实例里的可变变量是独立的,修改其中一个不会影响另一个。


内容的提问来源于stack exchange,提问作者jagprog5

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 21:10:22