【问题标题】:Using decorators in python to set global variables在python中使用装饰器设置全局变量
【发布时间】:2016-12-06 03:06:00
【问题描述】:

我正在尝试通过使用装饰器来减少 SLOC。我有一个案例,我需要启动四个 TCP 服务器并将连接的客户端保存为全局变量。这是代码。

# The sockets we will be using                                                             
socket0_client = None                                                                      
socket1_client = None                                                                      
socket2_client = None                                                                      
socket3_client = None                                                                      

# Populate them                                                                            
def save_client(global_client_var):                                                        
    def decorator(func):                                                                   
        async def inner(client, verbose=False):                                            
            global_client_var = client                                                     

            # Receive stuff                                                                
            with client:                                                                   
                while True:                                                                
                    # Get data.  If there is no data, quit                                 
                    data = await loop.sock_recv(client, 10000)                             
                    if not data:                                                           
                        break                                                              

                    # respond to the data                                                  
                    await func(client, data)                                               
        return inner                                                                       
    return decorator                                                                       

@save_client(socket0_client)                                                               
async def socket0_reply(client, data):                                                     
    await loop.sock_sendall(client, b'Got:'+data)                                          
@save_client(socket1_client)                                                               
async def socket1_reply(client, data):                                                     
    await loop.sock_sendall(client, b'Got:'+data)                                          
@save_client(socket2_client)                                                               
async def socket2_reply(client, data):                                                     
    await loop.sock_sendall(client, b'Got:'+data)                                          
@save_client(socket3_client)                                                               
async def socket3_reply(client, data):                                                     
    await loop.sock_sendall(client, b'Got:'+data)                                          

loop.create_task(tcp_server.single_server(('', 60001), task=socket0_reply, verbose=True))  
loop.create_task(tcp_server.single_server(('', 60002), task=socket1_reply, verbose=True))  
loop.create_task(tcp_server.single_server(('', 60003), task=socket2_reply, verbose=True))  
loop.create_task(tcp_server.single_server(('', 60004), task=socket3_reply, verbose=True)) 

有一个我没有代码的函数。它是 single_server 函数。它绑定到给定地址的服务器,等待连接,然后在新连接的客户端上调用任务。

我遇到的问题是,虽然客户端填充在内部函数中,并且明确设置为 global_client_var,但从未设置全局套接字。他们仍然没有。

这里发生了什么?如何设置这些全局变量?

【问题讨论】:

  • 为什么不在函数socket0_reply 中将socket0_client 声明为全局,然后将它们设置为客户端?
  • 因为在从套接字接收到数据之前不会调用该代码。即使在收到数据之前,我也希望能够在其他地方使用套接字。

标签: python sockets scope python-asyncio python-decorators


【解决方案1】:

您无法更新 Python 函数参数指向的引用,这是您的代码尝试执行的操作。 Python 中的所有函数调用参数都是按值传递的;但是,在这种情况下,您可以将项目附加到传入列表或字典中:

sockets = {}                                                                     

# Populate them                                                                            
def save_client(global_client_var):                                                        
    def decorator(func):                                                                   
        async def inner(client, verbose=False):                                            
            sockets[global_client_var] = client                                                     

            # Receive stuff                                                                
            with client:                                                                   
                while True:                                                                
                    # Get data.  If there is no data, quit                                 
                    data = await loop.sock_recv(client, 10000)                             
                    if not data:                                                           
                        break                                                              

                    # respond to the data                                                  
                    await func(client, data)                                               
        return inner                                                                       
    return decorator                                                                       

@save_client(0)                                                               
async def socket0_reply(client, data):                                                     
    await loop.sock_sendall(client, b'Got:'+data)                                          
@save_client(1)                                                               
async def socket1_reply(client, data):                                                     
    await loop.sock_sendall(client, b'Got:'+data)                                          
@save_client(2)                                                               
async def socket2_reply(client, data):                                                     
    await loop.sock_sendall(client, b'Got:'+data)                                          
@save_client(3)                                                               
async def socket3_reply(client, data):                                                     
    await loop.sock_sendall(client, b'Got:'+data) 

【讨论】:

  • 在这种情况下似乎不起作用。当我在将其设置为客户端之前添加“global global_client_var”行时,它在代码中的其他位置仍然具有值“None”。
  • 我误读了示例代码。在 Python 的函数调用中,所有参数都是按值传递的,不能用于更新变量绑定到的引用;但是,您可以传递诸如列表或字典之类的内容,这些内容可能会在集合中附加一个值。
  • 如果它是一本字典会更好。问题是我需要知道哪个套接字属于什么,而 append 方法不允许我跟踪。
  • 同意,使用字典并更新装饰器表达式以指定键与变量引用应该可以解决问题。
猜你喜欢
  • 1970-01-01
  • 2018-05-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-17
  • 1970-01-01
  • 1970-01-01
  • 2020-08-05
  • 2023-03-15
相关资源
最近更新 更多