🧩 附章 函数式语言是怎样工作的
📄 一句话概括

同一个 sum 换输入,结果类型自动跟着变,代码 0 处类型声明;但 Python 的注解既不检查也不推断——传字符串照样跑出 xy。

📝 本节和前面几节的关系

A.8 讲循环,这一节讲类型——功能式的第 7 条特征,也是 Python 最不给力的一条。

一、实测:类型跟着输入变

sum([1, 2, 3]) 得 6(int);sum([1.0, 2.0, 3.0]) 得 6.0(float);sum([True, True, False]) 得 2(int)。 同一个函数、同一份代码,类型由输入决定。 所以【自动推断】的好处不是省字,是省事。

二、Python 的注解是什么

只是记录:typed.__annotations__ 存下来,运行时不检查、不阻断。 也不推断:写 a + b 不会反推出 int。 实测 typed("x", "y") 返回 'xy'——注解写成 int,照样给你字符串。

三、真正的类型推断长什么样

编译期就把类型算出来:不写一个类型,编译器也知道每个表达式是什么。 好处:写起来像动态语言,出错却在编译期就拦下。 代价:推断不出来时要手写注解,报错信息也常常晦涩。

四、动手 Demo:特征7:编译器自动进行类型推断

同一个 sum 换三种输入,看结果类型。 再验 Python 的注解会不会被检查。

print(sum([1, 2, 3]), type(sum([1, 2, 3])).__name__)
print(sum([1.0, 2.0, 3.0]), type(sum([1.0, 2.0, 3.0])).__name__)
print(sum([True, True, False]))

def typed(a: int, b: int) -> int:
    return a + b

print(typed.__annotations__)
print(typed("x", "y"))         # xy  —— 注解没拦住

实跑输出:

--------------------------------------------------------------------
特征7:编译器自动进行类型推断
--------------------------------------------------------------------

  【自动推断】=不写类型,编译器自己算出来。**Python 是动态类型,只做到一半:**

      sum([1, 2, 3]) 得           6(int)
      sum([1.0, 2.0, 3.0]) 得     6.0(float)
      sum([True, True, False]) 得 2(int)

      同一个 sum 换了输入          结果类型自动跟着变,代码 0 处类型声明
      写上去的注解                a:int, b:int, return:int
      注解会被运行时检查吗        否(只记录,不阻断)
      注解会被自动推断吗          否(a + b 不会倒推出 int)
      强行传字符串                 'xy'

      这段代码在静态语言里要写的类型  4 处(参数 a、b、返回值、变量 s)
      在 Python 里实际写的类型        0 处(注解可省)

  **最大的区别在【什么时候知道类型】**:静态语言编译时知道,**Python 跑到那一行才知道。**
  **所以【自动推断】的好处不是省字,是省事**——**但代价是错误也推迟到运行时。**
  **注解在 Python 里是文档,不是保证**:`typed("x", "y")` 照样跑出 `xy`。

实测:sum 换输入类型自动跟变,代码 0 处类型声明。 Python 的注解只是记录:不检查、不推断,typed("x","y") 照样跑出 xy。 真正的类型推断在编译期就把类型算出来——像动态语言一样好写,却能在编译期拦错。

30 秒实验

  1. 给一个函数写全注解,再用错误类型调一次,看它会不会拦住。
  2. 想想为什么动态语言的错误总是跑到线上才炸。

常见误区

  1. 以为写了注解就有类型检查。Python 注解默认什么都不做。
  2. 把动态类型当成【没有类型】。类型还在,只是运行时才看。
自测三问(点开对答案) 1. sum 换输入后类型变吗? —— 变:整数得 int,浮点得 float,布尔得 int。 2. Python 的注解会被检查吗? —— 不会,只记录在 __annotations__ 里,也不做推断。 3. 类型推断的代价? —— 推断不出来时要手写注解,报错信息常晦涩。

相关笔记