查看原文
其他

为什么 Python 不用声明类型?

Python猫 2022-04-12

The following article is from 编程指北 Author 编程指北

作者:编程指北

来源:编程指北

变量为什么需要类型?

这个问题点像手机为什么叫手机,电脑为什么叫电脑,这种“日用而不知”的感觉。

为什么有些语言需要申明类型,而有些语言却不需要申明类型?

前者如 C/C++、Java,后者有 Python、JS 。

首先,在讨论为什么需要类型之前,先聊聊类型。

一、 类型

我们都知道,不管是中文、英文还是编程语言,都具有语法,语法规定了词怎么组成句子是符合规范的。

int a = 10;是可以的,但是a int = 10; 却不符合 C 语法规范。

10 + 10 是正确的,但是10 + “hello” 却是一个无效的表达式,但是该怎么判定呢?

答案就是「类型系统」,类型系统可以构建起一套判断表达式是否合法的规则。

对于每个变量都赋予一个类型,对于每种类型都定义了一组操作集合,而变量作为类型的实例,自然的继承了这些操作。

比如我们可以规定int + intstring + string 是合法的操作,直接禁止int + string等操作。

通过显示的将变量赋予类型,我们便可以在编译时去检查是否合法。

二、 变量

之前我在指针的那篇文章种说到:变量名是变量地址的符号化,变量名是为了让我们编程时更加方便,对人友好,可计算机可不认识什么变量 a,它只知道地址和指令。

所以当你去查看 C 语言编译后的汇编代码,就会发现变量名消失了,取而代之的是一串串抽象的地址。

可以认为,编译器会自动维护一个映射,将我们程序中的变量名转换为变量所对应的地址,然后再对这个地址去进行读写操作。

三、类型规定了什么?

我个人觉得类型首先是定义了一组操作,这是语法层面。

那所有的高级语言最后都会变成机器语言执行(解释型除外),再高级一点,那就是汇编,我们知道汇编语言是由一条条指令构成的。

而对于任何一条指令,最重要的有两点:数据的长度、数据在哪。

比如mov dest,src将一个字节从源地址 src 传送到目的地址 dest。

实际上,数据在哪就是地址,数据长度其实某方面就是取决于类型。

也正是这样,我之前在指针那篇文章中提到:指针的本质就是存储别的变量的地址,那么指针的类型是干什么用的呢?

是的,就是去访问指针所指向的地址的时候,指针的类型和指针的值(变量地址),提供了一条汇编指令最关键的两点:数据的长度和数据地址。

所以,类型除了提供语法检查以外,还能够明确变量所占据的内存空间。

同样也是规定了对字节的解释方式,同样 4 个byte,按照 int 和 float 类型解释得到的值完全不同。

更为本质的是,最终执行指令的 CPU 是区分了数据的类型的,不同的类型用不同的运算器,比如有 CPU 整形运算和 CPU 浮点型运算,不过浮点运算最为擅长的应该是 GPU。

也正是因为 CPU 区分了类型,上层的汇编、高级语言才需要区分变量的类型,CPU 基础决定了上层建筑。

四、 编译型&解释型

为什么 C/C++、Java 这类编译型语言就需要显示声明类型,而 Python 这类解释型语言就不需要呢?

所以是所有的编译型都需要申明类型?所有的解释型都不需要?

这个理解是不对的。

首先,“编译”和“解释”是语言实现的特征, 语言本身可以以任何一种方式实现。

可能我们大多只了解过 C 编译器(如GCC 、Clang ),却很少听过 C 解释器,如 Ch。

但是,即使使用 Ch 解释器,我们任然需要在 Ch 解释的 C 代码中申明类型。

为什么 Python 可以不用申明类型?

因为 Python 中的对象模型本身在运行时自带了“类型”这个信息,下面是 CPython 源码中关于对象的定义:

这个ob_type就是用来 Python 运行时检测变量类型的,而 Python 中的所有变量本质上都是一个对象的“指针”。

也正因为如此,Python 中的各种变量之间才能随意赋值,因为赋值的本质其实就是改变一下变量所指向的对象。

而真正到了解释执行的时候,Python 解释器就会取出这个类型字段,来判断操作是否符合语法,不符合的话就会运行时报错。

这个_typeobject 结构体的内部就定义了对象一系列的操作,比如 hashfunc、getattrfunc、setattrfunc等。

那么,为什么 C 即使是解释执行也需要申明类型呢?

很简单,因为 C 的对象模型中不会有”类型“这个字段,是 int 变量那直接就是 4 个字节,char 就 一个字节。

而 Python 的 int 变量,除了4 个字节的值本身以外,还需要占据一系列的描述类型的空间。

也就是说 C 语言运行时完全没有类型这种信息,所以需要在编译、解释的时候就带上。

之前偶尔会听到有人说 Python 是无类型的,这是完全错误的,看过这篇文章后,相信你一定不会说错了。

当然了,本文也只是简单的从粗浅的语法和实现层面解释了下,关于类型系统、类型推导等有人在研究的,这个也不是咱擅长的地方,感兴趣可以去搜一下。

Python猫注:关于 Python 的类型话题,推荐阅读:《Python到底是强类型语言,还是弱类型语言?》、《辨析编程语言的四种类型:动静类型与强弱类型》

Python猫技术交流群开放啦!群里既有国内一二线大厂在职员工,也有国内外高校在读学生,既有十多年码龄的编程老鸟,也有中小学刚刚入门的新人,学习氛围良好!想入群的同学,请在公号内回复『交流群』,获取猫哥的微信(谢绝广告党,非诚勿扰!)~


还不过瘾?试试它们




Python最佳代码实践:性能、内存和可用性!

Python在计算内存时应该注意的问题?

Python进阶:如何将字符串常量转为变量?

有了Python,我能叫出所有猫的名字

再谈文件读写:判断文件的几种方法及其优劣对比

Python猫荐书系统之四:《Python源码剖析》


如果你觉得本文有帮助
请慷慨分享点赞,感谢啦

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存