在导入时防止来自 运行 的代码

Prevent code from running at import time

如何在 CherryPy 网络应用程序启动时导入模块而不是在创建新 Process 时获取一些代码 运行?

我的 CherryPy 应用遵循以下模式:

Main.py

from Api1.Api1 import Api1
from Api2.Api2 import Api2
config = {'global': {'server.socket_host':  '0.0.0.0'}}
class Root():
    global config
    def __init__(self):
        self.app1 = App1('app1')
        self.app2 = App2('app2')
        config.update(self.app1.config)
        config.update(self.app2.config)

if __name__ == '__main__':
    cherrypy.quickstart(Root(), '/', config)

这里 if __name__ == '__main__': 完成它的工作:__name__ == '__main__' 当服务器启动时,__name__ == '__mp_main__' 当一个新的 Process 创建时,所以 cherrypy.quickstart()只发生一次。

App1\App1.py

def every_hour():
    [...]
Monitor(cherrypy.engine, every_hour, frequency=60 * 60).start()
db = peewee.SqliteDatabase('app1.db', threadlocals=True)
class App1():
    def __init__(self, root_dir):
        self.root_dir = root_dir
        my_path = os.path.dirname(__file__)
        self.config = {'/%s/css' % root_dir: {'tools.staticdir.on': True, 'tools.staticdir.dir': '%s\css' % my_path},
                       '/%s/img' % root_dir: {'tools.staticdir.on': True, 'tools.staticdir.dir': '%s\img' % my_path}}

这里同样的技巧不起作用,因为它总是 __name__ == 'App1.App1',因此在服务器启动和 Process(target=some_func).start() 时启动了一个新的 Monitor 并创建了一个新的数据库连接。

不在方法或 class 中的代码将在导入时 运行,因此如果您有一个文件 x.py 只写:

print("I'm just a poor boy, I need no sympathy")

并且你有另一个像你一样的文件导入这个文件,你甚至会在 main 或 init 启动之前看到这个文本的打印。

[编辑]回读我的回答可能有点笼统,但正因为如此,您的代码在 class 或函数之外:

Monitor(cherrypy.engine, every_hour, frequency=60 * 60).start()
db = peewee.SqliteDatabase('app1.db', threadlocals=True)

导入时也会 运行。

一个选择是将 App1.py 顶层的初始化代码移动到一个函数中,然后从 main.py 中的 if __name__ == "__main__": 守卫内部调用该函数]:

Main.py

from App1.App1 import App1, app1_init
from App2.App2 import App2
config = {'global': {'server.socket_host':  '0.0.0.0'}}
class Root():
    global config
    def __init__(self):
        self.app1 = App1('app1')
        self.app2 = App2('app2')
        config.update(self.app1.config)
        config.update(self.app2.config)

if __name__ == '__main__':
    app1_init()
    cherrypy.quickstart(Root(), '/', config)

App1.py

def every_hour():
    [...]

db = None
def app1_init():
    global db
    Monitor(cherrypy.engine, every_hour, frequency=60 * 60).start()
    db = peewee.SqliteDatabase('app1.db', threadlocals=True)

class App1():
    def __init__(self, root_dir):
        self.root_dir = root_dir
        my_path = os.path.dirname(__file__)
        self.config = {'/%s/css' % root_dir: {'tools.staticdir.on': True, 'tools.staticdir.dir': '%s\css' % my_path},
                       '/%s/img' % root_dir: {'tools.staticdir.on': True, 'tools.staticdir.dir': '%s\img' % my_path}}

这不是很理想,因为任何导入 App1 的东西都需要知道调用 app1_init,但它确实解决了这个问题。