2016-12-06 5 views
0

Я пытаюсь уменьшить SLOC с помощью декораторов. У меня есть случай, когда мне нужно запустить четыре сервера TCP и сохранить подключаемые клиенты в качестве глобальных переменных. Вот код.Использование декораторов в python для установки глобальных переменных

# 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, глобальные сокеты никогда не устанавливаются. Они остаются Нет.

Что здесь происходит? Как я могу установить эти глобальные переменные?

+0

почему не просто объявить 'socket0_client', как глобальная функция' socket0_reply' затем установить их на клиенте вместо этого? – Skycc

+0

, потому что этот код не будет вызываться, пока данные не будут получены из сокета. Я хочу иметь возможность использовать сокет в другом месте даже до получения данных. – jrk0414

ответ

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) 
+0

В этом случае это не работает. Когда я добавляю строку 'global global_client_var' до того, как я установил ее клиенту, она по-прежнему имеет значение «Нет» в другом месте кода. – jrk0414

+0

Я неправильно читаю код примера. В вызовах функций в Python все аргументы передаются по значению и не могут использоваться для обновления ссылки, к которой привязана переменная; однако вы можете передать что-то вроде списка или словаря, который может иметь значение, добавленное к коллекции. – joemeilinger

+0

Это будет работать лучше, если бы это был словарь. Дело в том, что мне нужно знать, какой сокет принадлежит чему, и метод append не позволит мне отслеживать. – jrk0414