问题背景:
动态类型从Python的早期版本就已经存在。这意味着变量在预先不绑定到特定数据类型,不像Java或C++等语言。类型是在执行时确定的。
问题:
主要的困难是失去了对类型的明确控制。这使得在编写代码时发现错误变得更加复杂,可能导致运行时逻辑错误,尤其是在代码扩展时。
解决方案:
Python通过鸭子类型(如果一个对象表现得像鸭子,那它就是鸭子)以及类型注解(type hints)来解决这个问题,然而类型注解不是强制的,在运行时不会被检查,仅由第三方工具来检查。
示例代码:
x = 42 # int x = "foo" # 现在是字符串 def process(val): return val + val print(process(5)) # 10 print(process("ha")) # haha
关键特点:
可以在同一代码块中先将一个变量用作列表,然后用作数字,这会导致语法错误吗?
可以 — 不会导致语法错误。只有在尝试使用新类型进行无效操作时才会出现错误。
x = [1, 2, 3] x = 5 # print(x[0]) # 只有在这个调用时会出错
Python中的类型提示是否保证变量在执行时始终具有指定的类型?
不 — 类型提示只是一个提示,解释器不会检查。只有linters和mypy才能检查类型。
def foo(x: int) -> int: return x + 1 foo("string") # 在调用之前不会报错
函数的类型也是动态的吗?可以在执行时改变函数的签名吗?
函数是一个一等对象。它的类型可以被重新定义,但签名不能被改变(可以用一个新的函数替换)。
def f(): return 5 f = lambda: "abc" print(f()) # 'abc'
负面案例
在一个项目中,函数的输入参数类型没有经过验证,导致用户表单中的数据以字符串形式到达,而与其作为数字进行操作。导致在生产环境中出现不可预测的错误。
优点:
快速原型制作,短小的函数,少量的样板代码。
缺点:
调试困难,错误在最意想不到的地方显现,并仅在特定数据下才会出现。
正面案例
通过使用类型提示和使用mypy进行静态类型验证,问题在CI/CD阶段就被发现,直到发布到生产。
优点:
早期发现潜在问题,代码易于维护。
缺点:
需要花费额外的时间进行检查,有时会增加一些多余的代码。