关于python中的循环引用
20220330
问题
被Github上的PyDracula项目写法迷惑了一天,主要是循环引用的问题。
实验
经验证,循环引用可以实现
#main.py
print('import b')
from main2 import *
print('b over')
class A:
a=0
def __init__(self):
B.set(self)
def set(self):
a=0
if __name__=='__main__':
ans=A()
print(ans.a)
#main2.py
print('import a')
from main import *
print('a over')
class B(A):
def set(self):
self.a=1
#运行结果
import b
import a
import b
b over
a over
b over
1
- 把
from main import *
改成from main import A
,结果一样。 - 把
from main2 import *
改成from main2 import B
,报错。
#改动2的结果
import b
import a
import b
Traceback....
可以看出main2都被导入了两次。* 和 * 之间不冲突,但是把 * 具体化就会陷入循环。我只能猜测* 有判别机制。
还有一个问题就是虽然A中有B,但是不能在主程序使用,在main中的对象可以调用A的东西 但是调用不了B的。
讨论
这种写法的优点:写程序时代码提示很方便
缺点:B中的self其实被A中的self顶替了,B在被调用的时候与函数没啥区别。
这写法就是钻python导入机制的bug,容易崩。导入两次同一个文件可太蠢了。东西都定义了两遍,运行就慢一倍,三个循环引用就是三倍时间。
我的改进写法
#main.py
print('import b')
from main2 import B
print('b over')
class A:
a=0
def __init__(self):
b=B(self)
b.set()
if __name__=='__main__':
ans=A()
print(ans.a)
#main2.py
class B:
b=1
def __init__(self,obj):
self.obj = obj
def set(self):
self.obj.a=1
#运行结果:
import b
b over
1
多简单。
这种写法优点:简单易懂执行快。
缺点:写的时候没有代码提示。
想要有代码提示的方法
写代码的时候用声明,白嫖代码编辑器的提示功能,用完注释
#from main import A
class B:
b=1
def __init__(
self,
obj#: A
):
self.obj = obj
def set(self):
self.obj.a=1