# 5.2.1 Python 是动态强类型语言

这句话其实说了两个概念： **Python 是动态类型语言**，以及 **Python 是强类型语言**，很多人会把这两组概念混淆。

首先，动/静态类型语言的区别在于类型被确认的时机。以 C 这类语言来说，编译器会检查变量的类型，比如 `int a = "hello";` 就无法通过编译，这就说明 C 语言是静态类型语言。而对于 Python 来说，`a = "hello"` 直到运行时，才会确定 a 引用的对象的类型是 `str`。

动态类型语言并非看上去没有类型标记那么简单，一方面，Swift 这样的语言支持类型推导，所以支持 `var s = "hello"` 这种写法，但这并不意味着 Swift 就是动态类型语言了，因为它的类型判断还是在编译期完成的，只不过编译器更加智能，可以推导出来而已。

另一方面，不在编译期检查类型并不意味着动态类型语言对类型的校验就是宽松的，这是另一个维度的衡量指标。如果语言对类型的校验很宽松，支持隐式转换，我们就称这种语言是 **“弱类型语言”**，否则就是**强类型语言**。强类型语言更严格，一定程度上语法会更啰嗦，弱类型语言代码更简单，更脚本化。以输出 "**My age is 22**" 为例：

```python
number = 22
string = 'My age is '
print(string + str(number))
```

这里必须把数字先转为字符串，才能和别的字符串拼接，这是因为 `str` 类的 `__add__` 函数只支持 `str` 类型的参数。可以看到，虽然数字（或者其他实现了 `__str__` 方法的自定义类）可以转为字符串，但这种转换必须是显式写明的，Python 并不支持隐式转换。

但用别的语言，比如 JavaScript 来实现类似的逻辑就非常简单了：

````python
number = 22
string = 'My age is '
console.log(string + number);
```python

可见，JavaScript 支持从数字到字符串的隐式转换。但这种隐式的转换也不一定是好事，比如再举一个例子：

```python
number = 22
string = '2'
console.log(string + number)
````

它的输出结果是 '222'，可见是把数字隐式的转成了字符串，然而如果我的本意是要把字符串转数字呢，比如这段代码在 PHP 中的输出就是 24：

```python
<?php
    $n = 22;
    $s = "2";
    print $s + $n
?>
```

因此，关于语言的强/弱类型，我想可以总结两点：

1. 类型的强弱是一个相对的概念，不像动态/静态类型那样有明确的判断标准。因为隐式转换可以发生在很多地方，有的语言支持的隐式转换场景很多，有的支持的场景很少，所以一般来说我们只能说某个语言的类型比较强（弱）或者说某个语言的类型比另一个语言更强（弱）。
2. 强弱类型没有优劣之分，强类型语言更严谨，不容易出现 Bug，但是代码复杂，书写成本高。弱类型语言更脚本化，写起来很简单，但很多规则并不那么显然，增加了学习成本。
