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

问题描述 投票:2回答:4

我有一个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中的设置,并在所需模块中访问此设置?
  • 根据塞巴斯蒂安的建议,另一种方法是在运行的进程之间共享变量。我本质上是想这样做。如何在python中执行此操作?

对于有兴趣知道为什么要这样做的人,请see this question。它说明了完整的系统设计以及所涉及的各个组件。

我也欢迎需要更改代码结构的建议。

python django python-2.7 celery
4个回答
2
投票

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

connection.py

multiprocessing

tasks.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()

0
投票

我没有使用django的经验,但是如果它们是从同一脚本执行的,则可以使Client单身,或者可以在init。py中声明Client,然后将其导入到任何需要的地方。

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

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)

然后您将定义:

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

这就是我所建议的所有简短描述。也许可以尝试更好地解释一切如何运行或涉及的部分。


0
投票

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

# 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

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


0
投票

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

# 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()

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

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

© www.soinside.com 2019 - 2024. All rights reserved.