I wish to extend Python socket.socket
with a new attribute (in particular, a queue.Queue
, but could be anything else). I am trying
to decide whether I should use inheritance or composition, but at some point both pose a
problem I am not sure how to solve:
A) If I use inheritance, with something like:
class MySocket(socket.socket):
def __init__(self, *args, **kwargs):
socket.socket.__init__(self, *args, **kwargs)
self.queue = queue.Queue()
then I have problems when I use operations like
connection, client_address = s.accept()
because the accept
method of sockets returns objects of type socket.socket
, and not of type MySocket
,
and I am not sure how to convert one into the other. If there is is a trivial OOP way to do this,
I do not know it.
B) The problem before is trivially solved if I used composition instead:
class MySocket(socket.socket):
def __init__(self, true_socket):
self.true_socket = true_socket
self.queue = queue.Queue()
I would simply implement something like
def accept(self, *args, **kwargs):
con, cli = socket.socket.accept(self, *args, **kwargs)
return self.__class__(con), cli
But then I have another problem. When I need to do
readable, writable, exceptional = select.select(inputs, outputs, inputs)
select
works for socket.socket
. With the A) version I would expect this to work just as is,
but with composition, now that MySockets
are not instances of socket.socket
, select
is broken.
So, what is the best, pythonistic approach for this?
EDIT: I forgot to say that the first thing I tried was to add the attribute directly to instances of `socket.socket':
s = socket.socket(...)
s.queue = queue.Queue()
but I got an exception saying the attribute is unknown for 'socket.socket'.
You can use the following, based on socket.socket.dup()
in Lib/socket.py
:
import _socket
class MySocket(socket.socket):
def __init__(self, *args, **kwargs):
super(MySocket, self).__init__(*args, **kwargs)
self.queue = queue.Queue
@classmethod
def copy(cls, sock):
fd = _socket.dup(sock.fileno())
copy = cls(sock.family, sock.type, sock.proto, fileno=fd)
copy.settimeout(sock.gettimeout())
return copy
You can now use the constructor to create new MySocket
s, or use MySocket.copy()
to create a MySocket
from an existing socket.socket
. Note that in most cases you should close the original socket after creating the copy.