gpt4 book ai didi

Python:即使以不同方式导入模块,也使类变量成为静态变量

转载 作者:太空狗 更新时间:2023-10-30 01:02:48 24 4
gpt4 key购买 nike

让我们考虑如下的包结构:

myApp
|-- myPackage
| |-- __init__.py
| +-- myModule.py
|-- __init__.py
+-- main.py

myModule.py 包含一个类,例如:

class MyClass( object ):
_myList = []

@classmethod
def test( cls ):
cls._myList.append( len( cls._myList ) )
return cls._myList

def __init__( self ):
return

pass

如您所见,没有什么特别的,我只是将列表定义为静态类变量。现在让我们考虑 main.py 中的代码:

from myApp.myPackage.myModule import MyClass as MyClassAbs
from myPackage.myModule import MyClass as MyClassRel

if __name__ == '__main__':

print '\n myList'
print 'MyClassAbs().test():', MyClassAbs().test() #< Prints [0].
print 'MyClassRel().test():', MyClassRel().test() #< Prints [0] but should be [0, 1].
print 'MyClassAbs.test():', MyClassAbs.test() #< Prints [0, 1] but should be [0, 1, 2].
print 'MyClassRel.test():', MyClassRel.test() #< Prints [0, 1] but should be [0, 1, 2, 3].

print '\n myList ids'
print id( MyClassAbs().test() )
print id( MyClassRel().test() )
print id( MyClassAbs.test() )
print id( MyClassRel.test() )

print ''
print 'MyClassAbs == MyClassRel:', MyClassAbs == MyClassRel #< Prints False
print 'isinstance( MyClassAbs(), MyClassRel ):', isinstance( MyClassAbs(), MyClassRel ) #< Prints False
print 'isinstance( MyClassRel(), MyClassAbs ):', isinstance( MyClassRel(), MyClassAbs ) #< Prints False

pass

问题是,在我的代码中,我从同一个模块中以不同的方式两次导入相同的类:一次作为绝对导入,一次作为相对导入。如代码的最后一部分所示,即使类相同,它们也不相等,因为它们的模块被独特地注册到 sys.modules 中:

'myApp.myPackage.myModule': <module 'myApp.myPackage.myModule' from '/full/path/myApp/myPackage/myModule.py'>
'myPackage.myModule': <module 'myPackage.myModule' from '/full/path/myApp/myPackage/myModule.py'>

因此,它们的表示不同:

'MyClassAbs': <class 'myApp.myPackage.myModule.MyClass'>
'MyClassRel': <class 'myPackage.myModule.MyClass'>

那么...有什么方法可以将此变量永久设置为静态变量吗?

编辑:
上面的代码显然只是对我的实际问题的简化。实际上,我基本上有一段代码可以递归地检查文件夹中嵌套的所有模块,并注册其中包含的类。然后可以使用通用语法实例化所有以这种方式注册的类,例如

myApp.create( 'myClass' )

这就是为什么我有时最终会有 2 个对象指向同一个类,但它们是以不同的方式导入的。一个已通过 imp.load_module() 调用自动导入,另一个将由用户通过常规导入语句直接导入。如果用户决定手动导入一个类,他应该仍然可以访问与在相同但自动注册的类中定义的静态类变量相同的静态类变量。希望它有意义?

最佳答案

没有。 (至少,并非没有非常丑陋和脆弱的技巧。)当您以这两种不同的方式导入它时,该模块实际上被导入了两次。如果您再次导入,Python 通常会重新使用已经导入的模块,但这不是基于导入的实际文件,而是基于相对于 sys.path 的路径。因此,如果您绝对地和相对地导入一次 myModule.py,整个文件实际上会执行两次。如果您执行以下操作,您可以看到这一点:

from myApp.myPackage import myModule
import myApp.myPackage.myModule as sameModule
import myPackage.myModule
print myModule is sameModule
print myModule is myPackage.myModule

对于第一次打印,您应该看到 True(因为前两次导入是通过相同的路径),但对于第二次打印,您应该看到 False(因为第三次导入使用不同的路径)小路)。这也是您在 sys.modules 中看到包含两个条目的模块的原因。

因为整个模块被导入了两次,所以您实际上有两个不同的类 MyClass,而不是一个。没有合法的方式让这两个类共享它们的状态。就好像您从两个不同的模块导入了两个不同的类一样。即使它们碰巧在同一个源文件中定义,当您像这样双重导入它们时,它们也不会以任何方式链接。 ( 有一种链接它们的邪恶方法,即您可以在模块中包含代码以手动检查它是否以不同的名称导入,然后手动弄乱 sys.modules 将当前导入的模块设置为已经导入的模块。但这是个坏主意,因为很难判断导入的模块是否真的是同一个模块,而且还因为踩踏 如果原始导入或新导入因任何原因失败,sys.modules 可能会导致奇怪的错误。)

真正的问题是,为什么要两次导入模块?第二个问题是,你为什么要使用相对导入?解决方案是使用绝对导入只导入一次模块,然后就没有问题了。

关于Python:即使以不同方式导入模块,也使类变量成为静态变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13392038/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com