有没有办法使用 Python RQ 从 __main__ 提交函数
Is there a way to submit functions from __main__ using Python RQ
与this question类似,有什么方法可以将同一文件中定义的函数提交给python-rq吗? @GG_Python 谁要我为此创建一个新问题。
用法示例:
# somemodule.py
from redis import Redis
from rq import Queue
def somefunc():
do_something()
q = Queue(connection=Redis('redis://redis'))
q.enqueue(somefunc)
是的,我知道答案是在 someothermodule.py 中定义 somefunc,然后在上面的代码片段 from someothermodule import somefunc
中定义,但我真的不想这样做。也许我对形式太执着了,但 somefunc 确实属于它排队的同一个文件(实际上,somefunc 采用 docker 容器名称并生成它)。我真的很希望整个事情都是独立的,而不是有两个模块。
我注意到,通过 python-rq 源代码挖掘,Queue.enqueue 实际上可以接受一个字符串而不是实际的模块,所以我希望我可以通过 somemodule.somefunc
,但没有那么幸运。有什么想法吗?
正在查看 the source, rq is just checking your function's __module__
attribute, which can be trivially changed. The question is, why does rq restrict you from enqueueing jobs from __main__
? There must be some reason, and there is: the function's module must be importable by the worker. __main__
is not, because your main module is not named __main__.py
on disk. See "Considerations for Jobs" toward the bottom of this page。
此外,您的脚本中包含 top-level (non-definition) 代码,每次由工作人员导入时都会重新调用,您可能不想这样做,因为它将创建新队列并在每个工作人员启动时无限地填充工作。如果你想在你的主模块中加入一个函数,你可以而且应该使用 if __name__ == "__main__"
守卫来防止这种递归行为。
如果您想将函数及其入队保留在单个模块中,我的建议是除了函数 and/or class 之外,不要在其中放入任何 top-level 代码定义。任何可能是 top-level 代码的东西,都写成一个函数(例如命名为 main()
)。然后编写一个 "dummy" 主模块,导入您的真实模块并开始处理。
示例:
somemodule.py
from redis import Redis
from rq import Queue
def somefunc():
do_something()
def main():
q = Queue(connection=Redis('redis://redis'))
q.enqueue(somefunc)
# if the user tried to execute this module, import the right one for them.
# somemodule is then imported twice, once as __main__ and once as somemodule,
# which will use a little extra memory and time but is mostly harmless
if __name__ == "__main__":
import mainmodule
mainmodule.py
import somemodule
somemodule.main()
您也可以只将函数的 __module__
属性更改为磁盘上模块的实际名称,以便可以导入它。您甚至可以编写一个装饰器来自动执行此操作:
from sys import modules
from from os.path import basename, splitext
def enqueueable(func):
if func.__module__ == "__main__":
func.__module__, _ = splitext(basename(modules["__main__"].__file__))
return func
@enqueueable
def somefunc():
do_something()
if __name__ == "__main__":
from redis import Redis
from rq import Queue
q = Queue(connection=Redis('redis://redis'))
q.enqueue(somefunc)
为简单起见,装饰器假定您的模块是单个文件,可在其文件名下导入,并删除 .py
扩展名。您可能 正在为您的主模块使用一个包,其中事情会变得更加复杂...所以不要那样做。
与this question类似,有什么方法可以将同一文件中定义的函数提交给python-rq吗? @GG_Python 谁要我为此创建一个新问题。
用法示例:
# somemodule.py
from redis import Redis
from rq import Queue
def somefunc():
do_something()
q = Queue(connection=Redis('redis://redis'))
q.enqueue(somefunc)
是的,我知道答案是在 someothermodule.py 中定义 somefunc,然后在上面的代码片段 from someothermodule import somefunc
中定义,但我真的不想这样做。也许我对形式太执着了,但 somefunc 确实属于它排队的同一个文件(实际上,somefunc 采用 docker 容器名称并生成它)。我真的很希望整个事情都是独立的,而不是有两个模块。
我注意到,通过 python-rq 源代码挖掘,Queue.enqueue 实际上可以接受一个字符串而不是实际的模块,所以我希望我可以通过 somemodule.somefunc
,但没有那么幸运。有什么想法吗?
正在查看 the source, rq is just checking your function's __module__
attribute, which can be trivially changed. The question is, why does rq restrict you from enqueueing jobs from __main__
? There must be some reason, and there is: the function's module must be importable by the worker. __main__
is not, because your main module is not named __main__.py
on disk. See "Considerations for Jobs" toward the bottom of this page。
此外,您的脚本中包含 top-level (non-definition) 代码,每次由工作人员导入时都会重新调用,您可能不想这样做,因为它将创建新队列并在每个工作人员启动时无限地填充工作。如果你想在你的主模块中加入一个函数,你可以而且应该使用 if __name__ == "__main__"
守卫来防止这种递归行为。
如果您想将函数及其入队保留在单个模块中,我的建议是除了函数 and/or class 之外,不要在其中放入任何 top-level 代码定义。任何可能是 top-level 代码的东西,都写成一个函数(例如命名为 main()
)。然后编写一个 "dummy" 主模块,导入您的真实模块并开始处理。
示例:
somemodule.pyfrom redis import Redis
from rq import Queue
def somefunc():
do_something()
def main():
q = Queue(connection=Redis('redis://redis'))
q.enqueue(somefunc)
# if the user tried to execute this module, import the right one for them.
# somemodule is then imported twice, once as __main__ and once as somemodule,
# which will use a little extra memory and time but is mostly harmless
if __name__ == "__main__":
import mainmodule
mainmodule.py
import somemodule
somemodule.main()
您也可以只将函数的 __module__
属性更改为磁盘上模块的实际名称,以便可以导入它。您甚至可以编写一个装饰器来自动执行此操作:
from sys import modules
from from os.path import basename, splitext
def enqueueable(func):
if func.__module__ == "__main__":
func.__module__, _ = splitext(basename(modules["__main__"].__file__))
return func
@enqueueable
def somefunc():
do_something()
if __name__ == "__main__":
from redis import Redis
from rq import Queue
q = Queue(connection=Redis('redis://redis'))
q.enqueue(somefunc)
为简单起见,装饰器假定您的模块是单个文件,可在其文件名下导入,并删除 .py
扩展名。您可能 正在为您的主模块使用一个包,其中事情会变得更加复杂...所以不要那样做。