我定义了一个Vector
类,它有三个属性变量:x
,y
和z
。坐标必须是实数,但没有什么可以阻止人们做以下事情:
>>> v = Vector(8, 7.3, -1)
>>> v.x = "foo"
>>> v.x
"foo"
我可以像这样实施“类型安全”:
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
......但这似乎不是Pythonic。
建议?
答案 0 :(得分:19)
你必须问自己为什么要在设置这些值时测试类型。只需在任何碰巧偶然发现错误的值类型的计算中提出TypeError
。奖励:标准操作已经这样做了。
>>> 3.0 / 'abc'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: unsupported operand type(s) for /: 'float' and 'str'
答案 1 :(得分:12)
Duck Typing是Python中的常用方法。它应该适用于任何表现的数字,但不一定 是实数。
在Python的大多数情况下,不应该明确检查类型。您可以获得灵活性,因为只要代码行为正确,您的代码就可以与自定义数据类型一起使用。
答案 2 :(得分:5)
其他答案已经指出,检查这里的类型没有多大意义。此外,如果用纯Python编写,你的课程将不会很快。
如果你想要一个更加pythonic的解决方案 - 你可以使用属性设置器,如:
@x.setter
def x(self, value):
assert isinstance(value, numbers.Real)
self.__x = value
当您禁用调试或启用优化模式时,将删除assert语句。
或者,您可以强制value
在setter中浮点。如果类型/值不可兑换,则会引发异常:
@x.setter
def x(self, value):
self.__x = float(value)
答案 3 :(得分:4)
但没有什么能阻止人们做以下事情:
我认为试图阻止某人做这样的事情是非Pythonic。如果必须,那么在我看来,在使用Vector
进行的任何操作期间,您应该检查类型安全。
引用G.V.R:
我们都是大人。
毕竟。有关详细信息,请参阅此question及其答案。
我相信更有经验的Pythonistas可以为您提供更好的答案。
答案 4 :(得分:2)
你不应该以这种方式提供类型安全。是的,有人可以通过提供容器无法工作的值来故意破坏您的代码 - 但这与其他语言相同。即使有人将一个参数的正确值放入一个方法或成员函数并不一定意味着它没有被破坏:如果一个程序需要一个IP地址,但你传递一个主机名,它仍然无法工作,尽管两者都可能是字符串。
我所说的是:Python的思维方式本质上是不同的。鸭子打字基本上说:嘿,我不仅限于某些类型,而是界面或对象的行为。如果一个物体确实表现得像我期望的那种物体那样,我就不在乎 - 只是去追求它。
如果您尝试引入类型检查,则基本上限制了该语言最有用的功能之一。
话虽这么说,你真的需要进入测试驱动开发,或至少进行单元测试。没有理由不使用动态语言 - 它只是将检测到的方式(类型)错误移动到构建过程的另一个步骤,从编译时间到每天多次运行测试套件。虽然这似乎是额外的努力,但它实际上会减少调试和修复代码所花费的时间,因为它是检测代码中错误的一种固有的更强大的方法。
但足够的,我已经在漫无边际了。