我仍然是Python的新手,我正在尝试习惯它的动态类型。有时我有一个函数或类需要某个类型的参数,但是可以得到另一个类型的值可以强制它。例如,它可能期望float
但是接收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))
我已经阅读了this answer和this one,他们说在Python中检查类型是“糟糕的”,但我不想浪费时间追踪非常简单的错误,这些错误会立即发生由编译器以静态类型语言提取。
答案 0 :(得分:8)
你“强迫”(或许 - 它可能是一个noop),当你这样做是必不可少的时候,而不是更早。例如,假设您有一个函数,它接受一个浮点数并返回其正弦和余弦的总和:
import math
def spc(x):
math.sin(x) + math.cos(x)
你应该在哪里“胁迫”x浮动?答案:无处可去 - 罪和cos为你做这项工作,例如:
>>> spc(decimal.Decimal('1.9'))
0.62301052082391117
那么当它是必不可少的来强迫(尽可能晚)?例如,如果要在参数上调用字符串方法,则必须确保它是一个字符串 - 尝试调用例如非字符串上的.lower
无法正常工作,len
可能会有效,但如果arg是例如,则会执行与您预期不同的操作。一个列表(给你列表中的项目数,而不是它表示为字符串的字符数),等等。
至于捕获错误 - 想想unit tests - 半单元测试将捕获静态类型会出现的所有错误,然后是一些错误。但是,这是一个不同的主题。
答案 1 :(得分:2)
这取决于。为什么需要 float
? int
会破坏这个功能吗?如果是这样,为什么?
如果您需要参数来支持float
但int
不具备float
的函数/属性,则应检查该函数/属性,不参数恰好是float
。检查对象是否可以执行您需要执行的操作,而不是它恰好是您熟悉的特定类型。
谁知道,也许有人会发现Python的notbrokenfloat
实现存在一些重大问题,并创建一个float
库。它可能支持浮动在修复一些异国情况的bug时所做的一切,但它的对象不是float
类型。手动将其转换为{{1}}可能会删除这个漂亮的新类的所有好处(或者可能会彻底破坏)。
是的,这是一个不太可能的例子,但我认为在使用动态类型语言时,这是正确的思维方式。
答案 2 :(得分:0)
只有一次整数与浮点数成为问题。这是唯一一次您会发现一个奇怪的“简单”错误并且是调试的挑战。
司
其他所有内容都会在您需要时进行转换。
如果你正在使用Python 2.x而不经意地随意抛弃/
运算符,你可以 - 在某些常见情况下 - 结束做错事。
您有多种选择。
from __future__ import division
将为您提供用于除法的Python 3语义。
始终使用-Qnew
选项运行以获得新的分区语义。
在float
操作附近使用/
。
分区是唯一类型可以重要的地方。这是整数与浮动的行为不同的唯一一次,它会以一种无声地影响结果的方式。
所有其他类型不匹配问题都会因TypeError
异常而失败。所有其他人。你不会浪费时间调试。你马上就会知道出了什么问题。
更具体。
没有调试“期望一个字符串,但没有得到一个字符串”。这将立即与追踪崩溃。没有混乱。没时间思念。如果函数需要一个字符串,那么调用者必须提供字符串 - 这就是规则。
上面的备选方案2使用RARELY来纠正问题,即你有一个函数需要一个字符串并且你感到困惑并忘了提供一个字符串。这个错误很快就会发生,它会导致一个直接的类型异常。