Python, Circular Dependencies, and Singletons

最后都变了- 提交于 2019-12-11 13:54:33

问题


I've dug myself into quite a hole here.

I'm working on a Python/Kivy app in PyDev.

The app runs off of many systems (about 10), so I shoved them into an engine to handle everything.

For ease of access, I grab the engine via (the worst) singletons

main.py

#main.py
from code import engine

class MyApp(App):
    def build(self):
        engine.GetInstance().Initialize()

if __name__ == '__main__':
    MyApp().run()

engine.py

#engine.py
from code import system1
from code import system2

gEngineInstance = None
def GetInstance():
    global gEngineInstance
    if (gEngineInstance == None):
        gEngineInstance = Engine()
    return gEngineInstance

class Engine():
    mSystem1 = None
    mSystem2 = None

    def Initialize(self):
        self.mSystem1 = system1.System1()
        self.mSystem2 = system2.System2()
    # Omitted

Unfortunatley, this resulted in some nasty circular dependencies.

Main has to create engine, and know about it, which runs engines imports, which runs the system imports. Problem: Systems imports then import engine, circular reference.

system1.py

#system1.py
from code import engine

class System1():
    def SomeMethod(self):
        engine.GetInstance().mSystem2.DoThings()

You get the picture. I bypassed this for now with this hideous code all over the place:

system1.py

#system1.py

class System1():
    def SomeMethod(self):
        from code import engine
        engine.GetInstance().mSystem2.DoThings()

This stops the import from happening until that line, which is fine, but it looks wrong, eveyrthing feels like i'm doing things wrong.

I'm tempted to just pass Engine as a reference to every systems constructor, but thats a bit of refactoring, and i'd like to know if there's a more decent way to fix this sort of singleton/circular reference issue for the future.


回答1:


How about having a "registration" mechanism, where each system module "registers" itself with the Engine class using some module-level code:

engine.py

class Engine():
    @classmethod
    def register(cls, type):
        ...

system1.py

from engine import Engine

class System1():
    ...

Engine.register(System1)

That way, the Engine doesn't directly have to know what gets plugged into it.



来源:https://stackoverflow.com/questions/15216424/python-circular-dependencies-and-singletons

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!