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

我一直在尝试将“_rcv_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,

    # ...

}

然后,在 ComManager 中:


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__,这远非理想,因为字典将包含数百个条目。


小怪兽爱吃肉
浏览 78回答 1
1回答

万千封印

你尝试过吗?如果您将import语句放在上面所示的方法中__init__,则不会出现“循环依赖”:在第一次导入另一个模块时,定义 ComManager 的调用者模块已经运行,并且该类已定义并准备好在第二个模块中导入。除此之外,您可以将处理方法放在 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, HandlerMixinclass 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
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python