【问题标题】:Initializing a subclass with an existing superclass instance in python3在python3中使用现有的超类实例初始化子类
【发布时间】:2019-10-12 22:04:59
【问题描述】:

我正在用 python 编写我自己的套接字类版本。 我想知道是否有办法使用它的__init__ 方法初始化子类,而是使用套接字类的现有实例来初始化它。

基本上,我想做的,就是继承socket类,覆盖accept()方法,返回我自己类的对象,而不是socket类。

为了解决这个问题,我想在我的自定义套接字类中的__init__ 方法中实现设置基本套接字的可能性,该方法将套接字的实例作为参数并创建我的新实例自定义套接字类,使用套接字类的现有实例,或使用fromSocket() 类方法执行相同操作。

我现在的问题是如何将套接字类的现有实例设置为我自己的套接字的超类而不使用属性来包含套接字对象? (这在 python 中甚至可能吗?)

我发现的所有其他相关问题更多是关于如何在运行时更改超类。我可能在某个地方忽略了答案,但我找不到。

我的代码如下所示:

import socket
class MySocket(socket.socket):
    def __init__(self, sock:socket.socket=None):
        if sock != None:
            # initialize using existing instance contained in sock
            # How? (My question)
        else:
            super().__init__() # Default conf is enough for now
    def accept(self):
        s, addr = super().accept()
        return MySocket(sock=s) # <= This is what I want to do

我想这样称呼它:

s = MySocket()
# Call bind and listen, left out because it doesn't matter here
client, addr = s.accept() 
# Client is an instance of socket.socket, but it should be MySocket

【问题讨论】:

    标签: python python-3.x sockets inheritance superclass


    【解决方案1】:

    这是socket.accept()的源代码。

    老实说,这看起来像是 socket 类的错误,他们已对其进行硬编码以创建 socket 的新实例:

    sock = socket(self.family, self.type, self.proto, fileno=fd)
    

    当它可能应该获取 self 的类型时:

    sock = type(self)(self.family, self.type, self.proto, fileno=fd)
    

    这似乎是通过多种方法完成的,看起来您最好的机会是将所有属性从返回的套接字手动复制到您的自定义实例。 dup() method 希望是正确的,因此我们可以创建一个重复其功能的类方法:

    import socket
    
    class MySocket(socket.socket):
        @classmethod
        def from_socket(cls, sock):
            fd = socket.dup(sock.fileno())
            my_sock = cls(sock.family, sock.type, sock.proto, fileno=fd)
            my_sock.settimeout(sock.gettimeout())
            return my_sock
    

    【讨论】:

    • 所以你的意思是基本上只是重写每个返回套接字对象的方法?而且没有办法从活动实例继承?
    • 该死,我这辈子都没用过socket,没想到有这么多方法可以返回socket 对象。好吧,您可以尝试创建某种包装类,也许它可以使用__getattr__ 调用getattr(self._socket, ...),然后检查返回值,如果它是socket 对象,您可以手动将其转换为MySocket 通过复制所有属性等...请问,您真正想要做什么?你需要一个自定义的MySocket 类来做什么?
    • 我想改变一些方法,比如发送方法,首先将消息的长度作为固定数量的字节发送,因此第二条(更长的)消息可以具有可变长度。所有这些都包含在一个方法中。我还想做一个包含在方法中的 Diffie Hellman Key Exchange。基本上,一旦套接字accept()s 成为新客户端,它就会进行密钥交换,并且从那时起就可以使用对称的 AES 密钥。我会将 AES 密钥作为套接字的一个属性(不知道这有多安全),所以我需要一个自定义类。
    • 好的。这不是我一直在寻找的答案,但它解决了我的问题。谢谢!
    • @J.Horr 是的,只是为了澄清你原来问题的答案:不,不可能直接从另一个实例初始化一个实例,除非类中有内置支持(例如我们的from_socket() 类方法)。这一切都归结为socket.socket 类中的一个错误,它应该只使用type(self) 来实例化新对象,而不是在那里硬编码socket
    【解决方案2】:

    所以你想要类似复制构造函数的东西。

    虽然有些事情表明 XY 问题,但有一个简单的替代方案(如果我做对了)。

    根据[Python 3.Docs]: socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)

    如果指定了 fileno,则自动检测 familytypeproto 的值指定的文件描述符。

    这似乎完全符合您的需要。

    注意:请记住,accept 返回一个元组,而您的覆盖不会,因此您的类 API 与其祖先的不兼容。

    这是一段应该做你想做的代码:

    class CustomSocket(socket.socket):
        def accept(self):
            conn, addr = super().accept()
            custom_conn = CustomSocket(conn.family, conn.type, conn.proto, conn.fileno())
            return custom_conn, addr
    

    【讨论】:

    • 这将要求 CustomSocket 具有与 socket.socket 类相同的构造函数,对吧?
    • 是的。我没有更改 ctor 中的任何内容,因为继承的似乎可以处理您想要的。看看我在accept中实例化socket的方式。
    猜你喜欢
    • 2016-06-13
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    • 2020-04-27
    • 1970-01-01
    • 1970-01-01
    • 2013-04-14
    • 1970-01-01
    相关资源
    最近更新 更多