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

2024-06-07 15:25:30 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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

在我的模块.py包含单个类,例如:

^{pr2}$

如您所见,没有什么特别之处,我只是将list定义为静态类变量。 现在让我们考虑主.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

问题是,在我的代码中,我从同一个模块导入了两次相同的类,但方式不同:一次作为绝对导入,一次作为相对导入。如代码的最后一部分所示,即使类是相同的,它们也不相等,因为它们的模块是以不同的方式注册到系统模块以下内容:

'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' )

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


Tags: 模块frompytestid静态myclassprints
2条回答

不需要(至少,不是没有非常丑陋和脆弱的黑客攻击)当你用这两种不同的方式导入它时,这个模块实际上被导入了两次。如果再次导入一个已经导入的模块,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(因为前两次导入是通过相同的路径),而第二次打印应该看到{}(因为第三次导入使用了不同的路径)。这也是您在sys.modules中看到包含两个条目的模块的原因。在

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

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

当涉及到python时,其他语言中的“静态”变量有很多需要回答的问题。我也发现这种思维方式让我的头在谈到这门语言时很受伤。在

很难说你的最终目标是什么,但值得注意的是,你可以创建一个“静态”变量(“咳嗽”变量“模块”变量?)在模块中声明它。所以myModule的结构可能类似于:

modList = []

class MyClass(object):
    def __init__(self):
        self._myList = [len(modList),]

    def appendLenToModList(self):
        modList.append(len(self._myList))

modList是在import上初始化的,应该作为一个singleton/static变量使用。如果您真的想直接处理它,我很确定您甚至可以使用名称空间myPackage.myModule.modList从myApp中使用它;但是一些访问器可以将其使用和用途形式化。在

相关问题 更多 >

    热门问题