在python中使用装饰器来设置全局变量

时间:2016-12-06 03:06:00

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

我试图通过使用装饰器来减少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,但从不设置全局套接字。他们仍然没有。

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

1 个答案:

答案 0 :(得分:0)

您无法更新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)