问题描述
我有一个处理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,threads for sending/receiving etc...
from x import _rcv_functions
这显然导致循环依赖。
我一直在寻找解决此问题的方法,有人建议使用类型提示,但在这种情况下我无法使其正常工作。
我还看到了一些答案,建议为每个字典值使用类似__import__('module_name').ComManager.class_method
的东西,但是我读到这会严重影响性能,因为每次我调用{{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,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