Python:将 class 中的字典 - 以 class 方法作为值 - 移动到另一个文件
Python: Move dictionary within a class - with class methods as values - to another file
我有一个处理 TCP 连接的 class,当收到具有给定“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__
,这远非理想,因为字典将包含数百个条目。
你试过了吗?
如果将 import
语句放在 __init__
方法中,如上所示,将不会有“循环依赖”:在第一次导入另一个模块时,定义 ComManager 的调用者模块已经 运行,并且 class 已定义并准备在第二个模块中导入。
除此之外,您可以只将处理方法放在混合 class 中,而不是放在处理程序 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
我有一个处理 TCP 连接的 class,当收到具有给定“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__
,这远非理想,因为字典将包含数百个条目。
你试过了吗?
如果将 import
语句放在 __init__
方法中,如上所示,将不会有“循环依赖”:在第一次导入另一个模块时,定义 ComManager 的调用者模块已经 运行,并且 class 已定义并准备在第二个模块中导入。
除此之外,您可以只将处理方法放在混合 class 中,而不是放在处理程序 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