在Python中输入安全性

24 python type-safety

我已经定义了一个Vector有三个属性变量类:x,yz.坐标必须是实数,但没有什么可以阻止人们做以下事情:

>>> v = Vector(8, 7.3, -1)
>>> v.x = "foo"
>>> v.x
"foo"
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

......但这似乎不是Pythonic.

建议?

kni*_*tti 18

您必须问自己为什么要在设置这些值时测试类型.只需TypeError在任何碰巧偶然发现错误类型的计算中引发a .奖励:标准操作已经这样做了.

>>> 3.0 / 'abc'
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: unsupported operand type(s) for /: 'float' and 'str'
Run Code Online (Sandbox Code Playgroud)

  • 然后编写一组全面的单元测试来运行代码的所有分支,以便在用户执行之前捕获TypeErrors.对?无论如何,关于什么时候应该抛出错误:如果你知道某个组合是无效的并且会引起问题,那么尽早失败会不会更好/更清楚?没有早期失败使得更容易找到根本问题?(我认为"为什么它无效"不太清楚.) (3认同)

Mad*_*ist 12

Duck Typing是Python中的常用方法.它应该适用于任何行为类似于数字的东西,但不一定实数.

在Python的大多数情况下,不应该明确检查类型.您可以获得灵活性,因为只要代码行为正确,您的代码就可以与自定义数据类型一起使用.


And*_*Dog 5

其他答案已经指出,检查这里的类型没有多大意义.此外,如果用纯Python编写,你的课程将不会很快.

如果你想要一个更加pythonic的解决方案 - 你可以使用属性设置器,如:

@x.setter
def x(self, value):
    assert isinstance(value, numbers.Real)
    self.__x = value
Run Code Online (Sandbox Code Playgroud)

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

或者,您可以强制value设置器中的浮点.如果类型/值不可转换,这将引发异常:

@x.setter
def x(self, value):
    self.__x = float(value)
Run Code Online (Sandbox Code Playgroud)