How to init 'MySocket' object with standart socket object?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP


How to init 'MySocket' object with standart socket object?



I want to write my own socket class for server-client talking with RSA and AES encryption, and for server side I need to overload accept() function to return not (socket, address) pair, but (MySocket, address). So that's why I need MySocket class to be initializable with another socket.



This is simplified version of my code:


import socket as sock

class MySocket(sock.socket):
def __init__(self, socket_obj = None):
if socket_obj == None:
sock.socket.__init__(self, family = sock.AF_INET, type = sock.SOCK_STREAM)
else:
assert(socket_obj.family == sock.AF_INET and socket_obj.type == sock.SOCK_STREAM)
self = socket_obj

self.key = 'value'

my_socket = MySocket() # works fine

print('First worked')

my_socket = MySocket(socket_obj = sock.socket()) # falls with error

print('Second also worked')



And after executing this code, I get an error:


Traceback (most recent call last):
File "./pyoverflow.py", line 19, in <module>
my_socket = MySocket(socket_obj = sock.socket()) # falls with error
File "./pyoverflow.py", line 13, in __init__
self.key = 'value'
AttributeError: 'socket' object has no attribute 'key'



As I understand, the problem is in the #9 string self = socket_obj, but googling the error didn't give anything.


self = socket_obj





This code doesn’t make any sense. Assigning a new value to self just rebinds the local variable self to another object for the rest of this function. So now, you’re calling self.key = value on that other object, which fails. But if it didn’t fail, you still wouldn’t have done anything to the MySocket you’re supposed to be initializing, but instead to the other object you rebound self to.
– abarnert
36 mins ago


self


self


self.key = value


MySocket


self




1 Answer
1



If MySocket is a subclass of socket, then a MySocket instance is a socket instance; it can't become a different socket instance, nor can you change another socket instance into a MySocket if it wasn't one already.1


MySocket


socket


MySocket


socket


socket


socket


MySocket



There are two possible things that do make sense here, however.



First, instead of being a socket, your MySocket can own a socket, and provide the same interface as the socket type by delegating calls to its owned socket. Then, you can easily choose whether to own a newly-created socket, or one that was passed in. Something like this:


socket


MySocket


socket


socket


socket


class MySocket:
def __init__(self, socket_obj = None):
if socket_obj is None:
socket_obj = socket.socket(self, family = sock.AF_INET, type = sock.SOCK_STREAM)
self._socket_obj = socket_obj
self.key = 'value'
def accept(self):
addr, sock = self._socket_obj.accept()
return addr, MySocket(sock)
def __getattr__(self, name):
if name.startswith('_'):
raise AttributeError(name)
return getattr(self._socket_obj, name)



Writing explicit delegators (whether manually, or by looping over inspect.getmembers(socket.socket) and creating them programmatically) is probably a better design here than __getattr__, but this gets the idea across.


inspect.getmembers(socket.socket)


__getattr__



The other option is to to do effectively what ssl.SSLSocket does.


ssl.SSLSocket



Socket objects are basically just a thin wrapper around a file descriptor. You can call detach on a socket to steal its fd, and then you can pass that fd into the socket constructor:


detach


socket


class MySocket(sock.socket):
def __init__(self, socket_obj=None):
if socket_obj is None:
super().__init__(family=sock.AF_INET, type=sock.SOCK_STREAM)
else:
super().__init__(fileno=socket_obj.detach())
self.key = 'value'



1. Actually, in Python, you can sometimes change the type of a live object, by setting its __class__ attribute. But this is almost always a bad idea, and wanting to do so is usually a sign that your design has gone very wrong somewhere.


__class__






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Stripe::AuthenticationError No API key provided. Set your API key using “Stripe.api_key = ”

CRM reporting Extension - SSRS instance is blank

Keycloak server returning user_not_found error when user is already imported with LDAP