【问题标题】:Best place to coerce/convert to the right type in Python在 Python 中强制/转换为正确类型的最佳位置
【发布时间】:2010-12-27 02:47:15
【问题描述】:

我对 Python 还是很陌生,我正在努力适应它的动态类型。有时我有一个函数或一个类,它需要一个特定类型的参数,但可能会得到另一个对其强制的类型的值。例如,它可能期望float,但会收到一个整数或小数。或者它可能期望一个字符串,而是接收一个定义__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))

我已经阅读了this answerthis one,他们说在 Python 中检查类型是“不好的”,但我不想浪费时间去追踪非常简单的错误,这些错误会立即被静态类型语言的编译器。

【问题讨论】:

  • 不要这样使用assert。断言用于记录在运行时不可能发生的条件,而不是用于验证输入。
  • 是的,除非有错误,否则不可能发生。在备选方案 3 中,调用者必须转换值,这将是一个错误。

标签: python dynamic-typing


【解决方案1】:

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

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

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

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

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

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

【讨论】:

    【解决方案2】:

    这真的取决于。为什么您需要floatint 会破坏这个功能吗?如果有,为什么?

    如果您需要参数来支持 float 具有但 int 不具有的函数/属性,您应该检查该函数/属性,该参数恰好是float。检查对象是否可以做你需要它做的事情,而不是它恰好是你熟悉的特定类型。

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

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

    【讨论】:

      【解决方案3】:

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

      部门。

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

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

      你有几个选择。

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

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

      3. / 操作附近使用float

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

      所有其他类型不匹配问题都会以TypeError 异常而失败。所有其他人。您不会浪费时间进行调试。您会立即知道出了什么问题。


      更具体。

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

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

      【讨论】:

      • 谢谢,很高兴知道选项 - 但 int/float 只是一个例子。还有其他问题的实例。
      • @Evgeny:真的吗?你能提供任何吗?唯一令人困惑的是 int/float。 AFAIK,除了明显的例外,所有其他人都死了。请提供一个不会因异常而死的操作示例。
      • 另一个例子是在我的原始帖子中:该方法可能需要一个字符串,但会接收一个定义 __str__ 特殊方法的对象。在某个地方我需要打电话给str(),但是在哪里?
      猜你喜欢
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 2020-08-04
      • 1970-01-01
      • 2019-11-04
      • 2011-04-30
      • 1970-01-01
      • 2014-02-04
      相关资源
      最近更新 更多