1

我对 Python 还是很陌生,我正在努力适应它的动态类型。有时我有一个函数或一个类,它需要一个特定类型的参数,但可能会得到另一个对其强制的类型的值。例如,它可能期望 afloat但接收的是 int 或小数。或者它可能期望一个字符串,而是接收一个定义__str__特殊方法的对象。

将参数强制为正确类型(及其原因)的最佳实践是什么?我是在函数/类中还是在调用者中执行此操作?如果在调用者中,我是否也在函数中检查它?例如。

备选方案 1:

def myfunc(takes_float):
    myval = float(takes_float)

myfunc(5)

备选方案 2:

def myfunc(takes_float):
    myval = takes_float

myfunc(float(5))

备选方案 3:

def myfunc(takes_float):
    assert isinstance(takes_float, float)
    myval = takes_float

myfunc(float(5))

我已经阅读了这个答案这个答案,他们说在 Python 中检查类型是“坏的”,但我不想浪费时间追踪非常简单的错误,这些错误会被编译器以静态类型的方式立即拾取语言。

4

3 回答 3

8

当你必须这样做时,你会“强制”(也许——它可能是一个 noop),而不是更早。例如,假设您有一个函数,它接受一个浮点数并返回其正弦和余弦之和:

import math
def spc(x):
  math.sin(x) + math.cos(x)

您应该在哪里“强制” x 浮动?答案:根本没有——sin 和 cos 为您完成这项工作,例如:

>>> spc(decimal.Decimal('1.9'))
0.62301052082391117

那么什么时候强制是必不可少的(越晚越好)?例如,如果你想在一个参数上调用字符串方法,你必须确保它是一个字符串——尝试.lower在一个非字符串上调用 eg 是行不通的,len可能会起作用,但如果arg 是例如一个列表(给你列表中的项目数,而不是它作为字符串表示将占用的字符数),等等。

至于捕捉错误——想想单元测试——半体面的单元测试将捕捉静态类型会捕捉到的所有错误,然后是一些。但是,这是一个不同的主题。

于 2009-12-16T05:34:12.637 回答
2

这真的取决于。为什么需要一个float?会int破坏功能吗?如果是这样,为什么?

如果您需要参数来支持 afloat具有但int不支持的函数/属性,则应检查该函数/属性,而不是参数恰好是 a float。检查该对象是否可以执行您需要它执行的操作,而不是它恰好是您熟悉的特定类型。

谁知道呢,也许有人会发现 Python 的实现存在一些重大问题float并创建了一个notbrokenfloat库。它可能支持 float 在修复一些奇异错误时所做的一切,但它的对象不会是 type float。手动将其转换为 afloat可能会消除这个漂亮的新类的所有好处(或者可能会彻底崩溃)。

是的,这是一个不太可能的例子,但我认为这是使用动态类型语言时的正确心态。

于 2009-12-16T05:39:27.820 回答
0

整数与浮点数确实有一次会成为问题。这是唯一一次您会发现一个“简单”的奇怪且难以调试的错误。

分配。

其他一切都会在您需要时进行您需要的转换。

如果您正在使用 Python 2.x 并且不假思索地随便乱扔/运算符,那么在某些常见情况下,您可能会做错事。

你有几个选择。

  1. from __future__ import division将为您提供 Python 3 除法语义。

  2. -Qnew始终使用该选项运行以获得新的除法语义。

  3. 使用float附近的/操作。

除法是唯一重要的地方。这是唯一一次整数的行为与浮点数不同,这种方式会默默地影响您的结果。

所有其他类型的不匹配问题都会失败,但有一个TypeError例外。所有其他人。您不会浪费时间进行调试。你会立即知道出了什么问题。


更具体。

没有“期望字符串但没有得到字符串”的调试。这将立即崩溃并带有回溯。没有混乱。没有时间浪费思考。如果一个函数需要一个字符串,那么调用者必须提供该字符串——这就是规则。

上面的备选方案 2 很少用于纠正您有一个需要字符串的函数并且您感到困惑并忘记提供字符串的问题。这个错误很少发生,它会导致立即类型异常。

于 2009-12-16T11:36:19.127 回答