8

我真的希望这不是重复的。我试图搜索我的问题,但似乎找不到。

所以我有一个相当简单的函数将英尺转换为米:

def feetToMeters(val):
    return numpy.array(val) * 0.3048

这很好用并且接受整数、浮点数、数组和列表。但是,如果我放入一个列表(而不是一个 numpy 数组),我希望返回一个列表。所以我写了这个:

def feetToMeters(val):
    try:
        return val * 0.3084
    except TypeError:
        return [0.3084 * v for v in val]

(或者return list(numpy.array(val) * 0.3084),如果我想在numpy这里使用,我可以使用最后一行,我不知道这是否真的很重要。)

这是在此处合并鸭子类型的最佳方法,以便我可以避免使用该type功能吗?最初我尝试过AttributeError,但没有奏效。TypeError尽管如此,即使它似乎有效,我仍然感到厌倦。

使用它会亵渎神明if type(val) is list吗?

4

4 回答 4

6

使用它会亵渎神明if type(val) is list吗?

是的,因为它不适用于列表的子类。如果你想走这条路,至少要这样做isinstance(val, list)。这是一个专门处理列表并将其他所有内容(包括标量和元组)转换为 NumPy 数组的解决方案:

def feetToMeters(feet):
    meters = np.asarray(feet) * 0.3048
    return list(meters) if isinstance(feet, list) else meters

注意:

  • 传递一个子类的实例list将导致一个普通list的被返回;
  • 传递列表列表将导致返回 NumPy 数组列表。

您可以扩展它以专门处理更多类型,但通常,对于要处理的每种类型,您需要编写更多代码,因为您需要知道如何构造该类型。因此,这种类型转换通常留给客户端代码。

于 2012-07-10T21:15:14.210 回答
3

由于您已经使用 numpy 我会避免在这里使用异常,例如

def feetToMeters(val):
    if numpy.isscalar(val):
        return val * 0.3084
    else:
        return numpy.array(val) * 0.3048
于 2012-07-10T21:15:00.500 回答
1

捕获 TypeError 很危险,因为它可能是由列表以外的许多事情引起的。为此,我通常会使用 isinstance(val, list) 。

于 2012-07-10T21:13:42.927 回答
0

诀窍是您正在尝试支持标量和序列-也许这样的东西对您有用:

def feetToMeters(val):
    try:
        return type(val)(val * 0.3048)
    except TypeError:
        return type(val)(v*0.3048 for v in val)
于 2012-07-10T21:15:38.167 回答