在 python3 中使用现有超类实例初始化子类

Initializing a subclass with an existing superclass instance in python3

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

基本上,我想做的是从套接字 class 继承,并将 accept() 方法覆盖为 return 我自己的对象 class而不是套接字 class.

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

我现在的问题是,如何在不使用属性包含套接字对象的情况下,将套接字 class 的现有实例设置为我自己套接字的超级class =36=]? (在 python 中甚至可能吗?)

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

我的代码看起来像这样:

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

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

老实说,这看起来像是 socket class 上的一个错误,他们已对其进行硬编码以创建 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 希望是正确的,因此我们可以创建一个重复其功能的 class 方法:

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

所以你想要类似于复制构造函数.

的东西

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

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

If fileno is specified, the values for family, type, and proto are auto-detected from the specified file descriptor.

这似乎正是您所需要的。

注意:记住接受returns一个元组,而你的覆盖没有,所以你的 class 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