Python:将类内的字典(类方法作为值)移动到另一个文件

2024-06-16 11:34:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个处理TCP连接的类,当接收到带有给定“ID”的消息时,我需要调用一个特定的函数来处理它。这些ID只是数字,所以我创建了一个IntEnum来保存这些ID:

class ID(IntEnum):
    # ...
    message_x = 20
    message_y = 21
    # ...

这些ID不一定是连续的(即,有些ID是保留的),我希望最终会有数百个甚至数千个ID

因为我不想为每个ID创建一千个if-else,所以我考虑将这些ID用作字典中的键,其中包含对处理每条消息的函数的引用:

class ComManager:

    def __init__(self):
        # Init socket, message queues, threads for sending/receiving etc...
        self.rcv_functions = {#...
                              ID.message_x: ComManager._rcv_message_x, 
                              ID.message_y: ComManager._rcv_message_y,
                              #...
                              }
        # Launch _rcv_thread here

    def _rcv_thread(self):
        message_id = self.rcv_message_id() # receive message ID from socket
        message_id = ID(message_id) # Change from type "int" to type "ID"
        self._rcv_functions[message_id](self) # Call appropriate method according to the dictionary, thus avoiding a massive if/else here or "switch case"-like workarounds

    def _rcv_message_x(self):
        # Handle reception and processing of message x here

    def _rcv_message_y(self):
        # Handle reception and processing of message y here

我一直在尝试将“\u rcv\u functions”放在它自己的文件中,因为每个消息都有一个函数已经够烦人的了:

# import ID and ComManager classes from their respetive files

_rcv_functions = {
    # ...
    ID.message_x:  ComManager._rcv_message_x,
    ID.message_y:  ComManager._rcv_message_y,
    # ...
}

然后,在CommManager中:

class ComManager:
    def __init__(self):
        # Init socket, message queues, threads for sending/receiving etc...
        from x import _rcv_functions

这显然会导致循环依赖

我一直在寻找这个问题的解决方案,有些人建议使用类型暗示,但在这种情况下,我无法让它工作

我还看到一些答案建议对每个字典值使用类似__import__('module_name').ComManager.class_method的东西,但我读到这会严重影响性能,因为每次调用__import__时都会处理整个文件,这远非理想,因为字典将包含数百个条目


Tags: 函数fromimportselfid消息message字典
1条回答
网友
1楼 · 发布于 2024-06-16 11:34:04

你试过了吗

如果将import语句放在上面所示的__init__方法中,则不会有“循环依赖”:在第一次导入另一个模块时,定义了CommManager的调用方模块已经运行,并且该类已经定义并准备在第二个模块中导入

除此之外,您可以将处理方法放在mixin类中,而不是放在处理程序ComManager本身的主体中

因此,在另一个模块中,您将有:


...
class ID(IntEnum):
    ...

class HandlersMixin:
    def _rcv_message_x(self, msg):
        ...
    ...

mapping = {
  ID.message_x = HandlerMixn._rcv_message_x,  
}

注意,通过这种方式,映射映射了未绑定的方法:它们是纯函数,期望“HandlerMixin”的实例作为其第一个参数

在您的第一个模块中:

from other_module import ID, mapping, HandlerMixin

class ComManager(HandlerMixin):
    def _rcv_thread(self):
        message_id = self.rcv_message_id() # receive message ID from socket
        message_id = ID(message_id) # Change from type "int" to type "ID"
        mapping[message_id](self)  
        # Passing "self" explictly will make the methods work the same
        # as f they were called from this instance as `self.method_name`,
        # and since they are methods on this class through inheritance
        # they can use any other methods or attributes on this instance

相关问题 更多 >