这是我想要实现的目标:
SKBusPacket
来创建数据包对象。 __init__()
中确定数据包的子类型,并根据此数据包的子类型引发异常("请求"或"响应"子类型。SKBusRequestPacket
或SKBusResponsePacket
。 问题:创建子类的实例将一次又一次地引发上述异常,因为我通过super
将初始化args传递给超类(参见代码)。
建议的解决方案:使用raise
检查实例是否是其中一个子类,以避免isinstance()
。但我的印象是,这是一种不好的做法,而且不是pythonic。
我的简化代码:
class SKBusPacket(Packet):
def __init__(self, *args, **kwargs):
super(SKBusPacket, self).__init__(*args, **kwargs)
self.packet_type = self.getSkbPacketType()
if self.packet_type == 'request':
raise ActuallySKBusReqPacket
elif self.packet_type == 'response':
raise ActuallySKBusPRPacket
# Here go some attributes and methods common to all packets...
# Both Request and Response packets inherit from base-class "SKBusPacket"
class SKBusRequestPacket
def __init__(self, *args, **kwargs):
# Pass init arguments to super-class "SKBusPacket".
super(SKBusRequestPacket, self).__init__(*args, **kwargs)
class SKBusResponsePacket
def __init__(self, *args, **kwargs):
# Pass init arguments to super-class "SKBusPacket".
super(SKBusResponsePacket, self).__init__(*args, **kwargs)
def log_skbus(raw_pkt):
try:
pkt = SKBusPacket(raw_pkt.data)
except ActuallyRequestPacket:
pkt = SKBusRequestPacket(raw_pkt.data)
except ActuallyResponsePacket:
pkt = SKBusResponsePacket(raw_pkt.data)
答案 0 :(得分:1)
最好将数据包类型的检测与实例化过程分开。如果有一个函数detect_type
,(类似于getSkbPacketType
方法)那么
def make_packet(raw_pkt):
packet_type = detect_type(raw_pkt.data)
if packet_type == 'request':
pkt = SKBusRequestPacket(raw_pkt.data)
elif packet_type == 'response':
pkt = SKBusResponsePacket(raw_pkt.data)
return pkt
将是您最干净的选择。
一个不太干净的选项是实例化SKBusPacket,检查packet_type
属性,然后实例化正确类型的数据包。请注意,不存在例外情况:
class SKBusPacket(Packet):
def __init__(self, *args, **kwargs):
super(SKBusPacket, self).__init__(*args, **kwargs)
self.packet_type = self.getSkbPacketType()
def log_skbus(raw_pkt):
pkt = SKBusPacket(raw_pkt.data)
if pkt.packet_type == 'request':
pkt = SKBusRequestPacket(raw_pkt.data)
elif pkt.packet_type == 'response':
pkt = SKBusResponsePacket(raw_pkt.data)
上述代码的一个问题是SKBusPacket.__init__
被调用两次,一次用于确定packet_type,第二次用于实例化SKBusRequestPacket或SKBusResponsePacket。也许呼叫很快,这种双重实例化过程不是主要的瓶颈。在这种情况下,这种解决方法就足够了。
如果没有,您可以通过动态更改实例的类来绕过正常的实例化过程:
def make_packet(raw_pkt):
pkt = SKBusPacket(raw_pkt.data)
if pkt.packet_type == 'request':
pkt.__class__ = SKBusRequestPacket
elif pkt.packet_type == 'response':
pkt.__class__ = SKBusResponsePacket
return pkt
要做到这一点,SKBusPacket必须是一个新式的类。
请注意,如果您以这种方式更改课程,SKBusRequestPacket.__init__
或SKBusResponsePacket.__init__
将被调用。它将允许pkt
访问这些类的方法,但是您需要在make_packet
函数本身中放置任何初始化代码。