Python 如何确保没有强类型的可靠合同?

Python 如何确保没有强类型的可靠合同?,python,python-2.7,types,duck-typing,dynamic-typing,Python,Python 2.7,Types,Duck Typing,Dynamic Typing,get\u min\u length()接受的参数必须与get\u pkt\u type()的可能返回值匹配。: 如果程序员向get\u pkt\u type()添加了一个新的数据包类型返回值,我如何确保他也不会忘记将该值添加到get\u min\u length()。在强类型语言中,数据包类型将是一种返回和传递的定义类型,因此这样我就有了安全性。无法确保程序员不会忘记任何东西。程序员是人,人往往会忘记事情 但是,您可以向get\u min\u length(数据包类型)添加一些代码,从而提醒程

get\u min\u length()
接受的参数必须与
get\u pkt\u type()的可能返回值匹配。


如果程序员向
get\u pkt\u type()
添加了一个新的数据包类型返回值,我如何确保他也不会忘记将该值添加到
get\u min\u length()
。在强类型语言中,
数据包类型将是一种返回和传递的定义类型,因此这样我就有了安全性。

无法确保程序员不会忘记任何东西。程序员是人,人往往会忘记事情

但是,您可以向
get\u min\u length(数据包类型)
添加一些代码,从而提醒程序员向该函数添加新值

else:
    print "Unknown packet type. Please add new value to the list."
    return some_int_value
或者,您甚至可以引发一个异常,以便程序员立即看到错误


在Python中,在调用函数之前必须定义函数

通常,在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 < /> >

你不应该这样做,即使你可以。 Python是一种

Duck-Typed
语言,在
Duck-Typed
语言中,我们不根据变量的类型限制变量。假设我定义了一个自定义<代码> PACTETHORION < /COD>如下:-< /P>
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
这就是鸭子打字的美妙之处,你添加了一个新的数据包,你根本不需要更改你的代码

回答您的问题-编写测试


这就是为什么测试在动态和弱类型语言中被认为非常重要的原因。我们不依赖强类型,最终编写的代码比需要的多得多,但我们在所有阶段都对代码进行了大量测试。添加新数据包的个人负责确保其代码正常工作,并且不会破坏您的代码。

您实际上可以在python中创建自己的类型-类型只是类

class packet_type(object):
  def __init__(self, name, length):
    self.name = name
    self.length = length

CMD = packet_type("CMD", 4)
有时,这可能看起来有点沉重。一个更简单的选择是将属性转储到原始数据结构中,如Veedrac的回答所示。 如果你只想要一个像容器一样的结构,这是一个很好的折衷方案


所有这些选项都有一个优点,即参数直接在对象上定义,它们实际上属于对象。这意味着只有一个点需要定义新参数(在新实例上),而不是设置中的几个。duck类型也可以更好地使用它,因为任何具有
名称
长度
的类,无论扩展名如何,都可以使用。

在这里应该
提高ValueError
。在Python中不能。但是,如果您有一个完整的有效数据包列表,您可以添加一个unittest,确保您的所有函数都接受有效的数据包类型。非常感谢您富有洞察力的回答。我想知道你为什么建议使用
Enum
而不是set或tuple。我假设
Enum
将保存所有数据包类型“CMD”、“RES”等。但是Enum对每个项目都有一个关联的值(但在我的上下文中不存在这样的值)。那么,为什么枚举适用于此呢?将为
数据包类型生成真正的单例,将为您提供一个类型不太严格的接口,并允许您检查唯一性等内容并获得有效值列表。如果您不想使用关联的值,您不需要关心它们。FWIW,您的
SpecialPacket
可能也应该实现
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu hash
@Veedrac。这只是一个示例来说明这一点。这是不可能的,兄弟
class packet_type(object):
  def __init__(self, name, length):
    self.name = name
    self.length = length

CMD = packet_type("CMD", 4)
from collections import namedtuple
packet_type = namedtuple('packet_type', ['name', 'length']
CMD = packet_type("CMD", 4)