如何用动态打字保护

时间:2012-09-08 15:55:12

标签: python dynamic-typing

当我尝试向函数添加一条简单的错误消息时,我的项目变得越来越大了,有一天我遇到了这个问题:

def create_report(id):
    report = new_report(id)
    if not report:
        raise api_error('Could not find report with id %d' % (id,))
    ...

问题? id是一个字符串,它在尝试将其格式化为数字时崩溃了。我不是该函数的原始作者,错误地认为id将是一个数字。相反它应该是一个字符串。糟糕。

如果这是一种强类型语言,我会立即从编译器中得到错误;这些事情最好的方法是什么?我应该检查每个参数的类型(看起来像很多腿部工作),还是应该把所有参数放在try:块中?也许我们应该在描述它的参数的每个函数中写一个注释?或者我本来应该知道更好?

6 个答案:

答案 0 :(得分:2)

该格式字符串应该使用%s,而不是因为id是字符串,但因为它通常是最佳选择。 %d需要数字类型,但如果需要,%s会将其他类型转换为字符串。只有在需要更改数字格式时才应使用%d

答案 1 :(得分:0)

使参数类型更加健壮的可能策略是写:

def create_report(id):
    report = new_report(id)
    if not report:
        raise api_error('Could not find report with id %s' % (id,))
    ...

它看起来并不总是很好,但至少它不会轻易破坏。

但总的来说,与函数签订一些明确的合同总是更好。 docstring是正确的地方。

答案 2 :(得分:0)

如果你真的想确保字符串打印功能不会崩溃,你可能最好使用%s,它使用pythons str() - function将积分值转换为字符串。 看看你正在谈论它是一个ID,我会假设它是int类型 - 在这种情况下这个解决方案应该可以正常工作(如果你使用浮点数,我不太确定有多少个数字str()将继续)。

修改的 噢,小伙子,我很慢......

答案 3 :(得分:0)

尝试使用%s然后使用str(变量)。这将确保所有内容都转换为字符串(甚至列表和元组)并且不会发生TypeError

def create_report(id):
    report = new_report(id)
    if not report:
        raise api_error('Could not find report with id %s' % (str(id),))
    ...

答案 4 :(得分:0)

甚至比其他答案'%s更好,我发现使用%r是最好的,如果该消息是供开发人员使用的话。这有助于您区分细微的案例。例如,如果使用'12 '为id调用此函数,则%s消息将不显示尾随空格。 %r使用值的repr(),因此将包含引号,帮助您查看精确值。

答案 5 :(得分:0)

我认为这里的问题是你断言某些代码中的值,当发生意外事件时应该执行该代码。也许更好的方法是更改​​new_report(id)以在出现问题时引发异常 - 指定它是否为值错误或无法找到id。然后你的代码应该是:

def create_report(id):
    report = new_report(id)

...

def new_report(id):
    try:
       # find the report by id
       # if couldn't find raise api_error
    except ValueError:
       # explain that id is the wrong type