Python中的类型安全

Type safety in Python

我定义了一个Vector类,它有三个属性变量:xyz。坐标必须是实数,但没有什么可以阻止一个人执行以下操作:

1
2
3
4
>>> v = Vector(8, 7.3, -1)
>>> v.x ="foo"
>>> v.x
"foo"

我可以像这样实现"类型安全:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import numbers

class Vector:
    def __init__(self, x, y, z):
        self.setposition(x, y, z)

    def setposition(self, x, y, z):
        for i in (x, y, z):
            if not isinstance(i, numbers.Real):
                raise TypeError("Real coordinates only")

        self.__x = x
        self.__y = y
        self.__z = z

    @property
    def x(self):
        return self.__x

    @property
    def y(self):
        return self.__y

    @property
    def z(self):
        return self.__z

…但那似乎不是Python。

建议?


您必须问自己为什么要在设置这些值时测试类型。只需在任何计算中提高一个TypeError,而该计算恰好会被错误的valuetype绊倒。奖励:标准操作已经做到了。

1
2
3
4
>>> 3.0 / 'abc'
Traceback (most recent call last):
  File"<stdin>", line 1, in ?
TypeError: unsupported operand type(s) for /: 'float' and 'str'


鸭子打字是Python常用的方法。它应该适用于任何类似于数字的行为,但不一定是实数。

在大多数情况下,在Python中不应该显式地检查类型。您获得了灵活性,因为您的代码可以与自定义数据类型一起使用,只要它们的行为正确。


其他答案已经指出,在这里检查类型没有多大意义。此外,如果你的类是用纯Python编写的,那么它就不会非常快。

如果你想要一个更为Python式的解决方案,你可以使用如下属性设置器:

1
2
3
4
@x.setter
def x(self, value):
    assert isinstance(value, numbers.Real)
    self.__x = value

禁用调试或启用优化模式时,将删除assert语句。

或者,您可以在setter中强制value到浮点。如果类型/值不可转换,则会引发异常:

1
2
3
@x.setter
def x(self, value):
    self.__x = float(value)

But there's nothing to stop one from doing the following:

我相信试图阻止某人做这种事是不可能的。如果必须,那么在我看来,在使用Vector进行任何操作时,都应该检查类型安全性。

引用G.V.R:

we are all adults.

毕竟。有关详细信息,请参阅此问题及其答案。

我相信这里经验丰富的Python师会给你更好的答案。


你不应该这样提供类型安全。是的,有人可以故意通过提供容器不起作用的值来破坏代码,但这与其他语言是一样的。即使有人将一个参数的正确值放入一个方法或成员函数中,并不一定意味着它没有被破坏:如果一个程序需要一个IP地址,但您传递了一个主机名,它仍然不能工作,尽管这两个参数都可能是字符串。

我要说的是:Python的思维方式本质上是不同的。duck输入法基本上是这样说的:嘿,我不局限于某些类型,而是对象的接口或行为。如果一个物体的行为真的像我所期望的那样,我不在乎——去追求它。

如果您试图引入类型检查,那么您基本上是在限制该语言最有用的特性之一。

也就是说,您确实需要进入测试驱动开发,或者至少是单元测试。确实没有理由不使用动态语言来完成这项工作——它只是将检测(类型)错误的方式转移到构建过程中的另一个步骤,从编译时间到每天多次运行测试套件。虽然这看起来像是额外的工作,但实际上它将减少调试和修复代码的时间,因为这是检测代码中错误的一种固有的更强大的方法。

但够了,我已经在闲逛了。