为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

小怪兽爱吃肉 2023-07-18 15:34:57
我有一个处理 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__,这远非理想,因为字典将包含数百个条目。
查看完整描述

1 回答

?
万千封印

TA贡献1891条经验 获得超3个赞

你尝试过吗?


如果您将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, 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


查看完整回答
反对 回复 2023-07-18
  • 1 回答
  • 0 关注
  • 75 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信