访问在脚本主模块中定义的python类变量

时间:2014-09-01 14:22:18

标签: python django python-2.7 celery

我有一个django项目,它使用celery进行异步任务处理。我使用的是python 2.7。

我的django项目中的模块client.py中有一个类:

# client.py
class Client:
    def __init__(self):
        # code for opening a persistent connection and saving the connection client in a class variable
        ...
        self.client = <connection client>

    def get_connection_client(self):
        return self.client

    def send_message(self, message):
        # --- Not the exact code but this is the function I need to access to for which I need access to the client variable---
        self.client.send(message)
    # Other functions that use the above method to send messages
    ...

此类只需实例化一次即可创建一个与远程服务器的持久连接

我运行一个无限期运行的脚本connection.py

# connection.py
from client import Client
if __name__ == '__main__':
    clientobj = Client()
    client = clientobj.get_connection_client()
    # Blocking process
    while True:
        # waits for a message from the remote server
        ...

我需要从另一个模块client访问变量tasks.py(芹菜需要)。


# tasks.py
...
from client import Client
@app.task
def function():
    # Need access to the client variable
    # <??? How do I get an access to the client variable for the 
    # already established connection???>
    message = "Message to send to the server using the established connection"
    client.send_message(message)

所有三个python模块都在同一台机器上。 connection.py作为独立脚本执行并首先执行。 function()中的方法tasks.py在项目的其他模块中被调用多次,因此,我无法在此方法中实例化Client类。全局变量不起作用。


在java中,我们可以创建全局静态变量并在整个项目中访问它。我们如何在python中执行此操作?

方法我可以想到但不确定它们是否可以在python中完成:

  • 将此变量保存在公共文件中,以便在项目的其他模块中可以访问它?
  • 将此客户端保存为django或celery中的设置,并在所需模块中访问此设置?
  • 根据sebastian的建议,另一种方法是在正在运行的进程之间共享变量。我基本上想要这样做。我如何在python中执行此操作?

如果有兴趣知道为什么需要这些,请see this question。它解释了完整的系统设计和涉及的各种组件。

我愿意接受需要改变代码结构的建议。

5 个答案:

答案 0 :(得分:2)

multiprocessing提供了执行此操作所需的所有工具。

<强> connection.py

from multiprocessing.managers import BaseManager
from client import Client()
client = Client()
class ClientManager(BaseManager): pass
ClientManager.register('get_client', callable=lambda: client)
manager = ClientManager(address=('', 50000), authkey='abracadabra')
server = manager.get_server()
server.serve_forever()

<强> tasks.py

from multiprocessing.managers import BaseManager
class ClientManager(BaseManager): pass
ClientManager.register('get_client')
manager = ClientManager(address=('localhost', 50000), authkey='abracadabra')
manager.connect()
client = manager.get_client()

@app.task
def function():
    message = "Message to send to the server using the established connection"
    client.send_message(message)

答案 1 :(得分:0)

我没有使用django的经验,但是如果它们是从同一个脚本执行的,那么你可以让客户端成为单例,或者可以在 init .py中声明客户端,然后将其导入到任何地方你需要它。

如果你选择单身人士,你可以为此做一个装饰:

def singleton(cls):
    instances = {}

    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return get_instance

然后你会定义:

# client.py

@singleton
class Client:
    def __init__(self):
        # code for opening a persistent connection and saving the connection client in a class variable
        ...
        self.client = <connection client>

    def get_connection_client(self):
        return self.client

这就是我所能提出的所有内容。也许试着更好地解释一切运行​​方式或涉及的部分。

答案 2 :(得分:0)

Python具有类属性(在实例之间共享的属性)和类方法(作用于类本身的方法)。两者在类和实例上都是可读的。

# client.py
class Client(object):
    _client = None

    @classmethod
    def connect(cls):
        # dont do anything if already connected
        if cls._client is None:
            return

        # code for opening a persistent connection and saving the connection client in a class variable
        ...
        cls._client = <connection client>


    @classmethod
    def get_connection_client(cls):
        return cls._client


    def __init__(self):
        # make sure we try to have a connection on initialisation
        self.connect()

现在我不确定这是解决问题的最佳方法。

答案 3 :(得分:0)

如果connection.py正在导入tasks.py ,则可以在tasks.py中进行:

import __main__ # connection.py
main_globals = __main__.__dict__ # this "is" what you getting in connection.py when you write globals()
client = main_globals["client"]  # this client has the same id with client in connection.py

BaseManager也是一个答案,但它在localhost上使用套接字网络,如果您尚未使用多处理程序,则它不是访问变量的好方法。我的意思是,如果需要使用多重处理,则应该使用BaseManager。但是,如果您不需要多重处理,则不是使用多重处理的好选择。我的代码只是从中获取connection.py中“ client”变量的指针 解释器。

如果您要使用多重处理,我的代码将无法正常工作,因为不同进程中的解释器不同。

答案 4 :(得分:-1)

从文件中读取时使用pickle