Pere
Pere

Reputation: 429

How to instance a class in a loop in Python

I have a simple chat application with server and client code in Python. In the server side the class Client defines the following

class Client(object):
    def __init__(self, socket, address):
     self.sock = socket
     self.addr = address
     self.room = None
     self.name = None
     self._is_online = True
     thread = threading.Thread(target=self.run, args=())
     thread.daemon = True
     thread.start()

As you can see the server handles every client as a different thread. On the main thread the server runs in a always-true loop

while True:
(ready_to_read, _, _) = select.select([server_sckt] + [Client.sock for Client in clients], [], [])
for connection in ready_to_read:
    if connection == server_sckt:
        (connection, address) = server_sckt.accept()
        clients.append( Client(connection, address) )

clients is the list containing all Client objects. The problem comes in the second loop iteration.

Traceback (most recent call last):
 File "servidor_class.py", line 215, in <module>
  clients.append( Client(connection, address) )
TypeError: 'Client' object is not callable

So it's clear I'm not getting pythonic OOP way to declare each instance.

I've looked another related questions:

  1. Creating object instances in a loop with independent handling
  2. Python creating multiple instances for a single object/class

But I'm still not seeing my mistake instancing, sure it's in front of me. Without appending to a list seems to work but main server functionalities like send message to all online people or check if username if already used doesn't work.

Upvotes: 0

Views: 198

Answers (1)

FamousJameous
FamousJameous

Reputation: 1585

In Python 2, list comprehensions leak the control variable: See this question

The problem is a few lines above where the exception actually happens in the select line

#                                                                      | Here
#                                                                      v
(ready_to_read, _, _) = select.select([server_sckt] + [Client.sock for Client in clients], [], [])

In the list comprehension you redefine what Client means. It becomes an instance of the Client class. So when you try to create another instance using an existing instance instead of a class, it raises an exception.

Change the list comprehension part to

#                | notice the lower case.
#                v
[client.sock for client in clients]

Or anything else besides Client

Upvotes: 3

Related Questions