get_min_length()
接受的参数必须与get_pkt_type()
的可能返回值匹配:
def get_pkt_type(some_val):
"""Determine the type of an XCP packet.
:return:
'CMD' if "Command" packet,
'RES' if "Command Response" packet,
'ERR' if "Error" packet,
'CMD/RES' if uncertain whether a CONNECT CMD or a
RES packet, as their frame bytes can look identical.
:rtype: str
"""
if something:
return 'CMD'
elif something_else2:
return 'RES'
elif something_else3:
return 'ERR'
elif something_else4:
return 'CMD/RES'
def get_min_length(packet_type):
if packet_type in ['CMD', 'RES']:
return 4
elif packet_type in ['ERR', 'CMD/RES']:
return 6
packet_type = get_pkt_type(some_val)
length = get_min_length(packet_type)
如果程序员将新的数据包类型返回值添加到get_pkt_type()
,我如何确保他也不会忘记将值添加到get_min_length()
。在强类型语言中,packet_type
将是一个返回并传递的已定义类型,因此我会保持安全。
答案 0 :(得分:1)
通常,在Python中,如果您有一组可扩展的值,那么建立一个浅层继承层次结构是有意义的。这不容易忘记。对于固定的值集,枚举更好。
那就是说,你应该做的第一件事是尾随
raise ValueError("Unexpected enum value")
到您的职能部门。
您可能会考虑使用字典来表示此类映射:
pkt_lengths = {
'CMD': 4,
'RES': 4,
'ERR': 6,
'CMD/RES': 6,
}
get_min_length = pkt_lengths.__getitem__
然后您可以添加一个简单的测试
packet_types = {'CMD', 'RES', 'ERR', 'CMD/RES'}
assert not packet_types.symmetric_difference(pkt_lengths)
如果您经常这样做,请构建一个函数:
def enum_mapper(enum, mapper):
assert not enum.symmetric_difference(mapper)
return mapper.__getitem__
可以让你做到
get_min_length = enum_mapper(packet_types, pkt_lengths)
并在启动时获得检查。
另外,请考虑使用正确的enum.Enum
。
答案 1 :(得分:1)
即使你可以,你也不应该这样做。
Python是一种Duck-Typed
语言,使用duck-typed
语言,我们不会根据类型限制变量。考虑我定义自定义packet_type
的情况如下: -
class SpecialPacket(object):
def __init__(self, value):
self.value = value
def __eq__(self, other):
return self.value == other
special_packet = SpecialPacket('CMD')
print(get_min_length(special_packet))
# 6
这就是duck-typing
的美妙之处,您添加了一个新数据包,而您根本不需要更改代码。
回答你的问题 - 写测试
这就是为什么测试在动态和弱类型语言中被认为非常重要的原因。我们不依赖于强类型,最终编写了比我们需要的代码更多的代码,而是在所有阶段对代码进行了大量测试。添加新数据包的个人有责任确保他的代码有效,并且他最终不会破坏您的代码。
答案 2 :(得分:1)
你实际上可以在python中创建自己的类型 - 类型只是类。
class packet_type(object):
def __init__(self, name, length):
self.name = name
self.length = length
CMD = packet_type("CMD", 4)
有时,这看起来有点沉重。更简单的替代方法是将属性转储到原始数据结构中,如Veedrac的答案。 如果你只想要一个类似结构的容器,那么非常好的中间地带是namedtuples。
from collections import namedtuple
packet_type = namedtuple('packet_type', ['name', 'length']
CMD = packet_type("CMD", 4)
所有这些选项的优点是参数直接在对象上定义,它们实际属于它们。这意味着只有一个点需要定义新参数(在新实例上),而不是在您的设置中。对于鸭子打字,它也可以更好地使用,因为任何具有name
和length
的课程都可以使用。
答案 3 :(得分:0)
没有办法确保程序员不会忘记任何事情。程序员是人,人往往会忘记事物。
但是,您可以向get_min_length(packet_type)
添加一些代码,从而提醒程序员将新值添加到此函数中。
else:
print "Unknown packet type. Please add new value to the list."
return some_int_value
或者您甚至可以引发异常,因此程序员立即看到错误。
PS。在Python中,您必须在调用它们之前定义您的函数。