1。动态类型和静态类型以及强类型和弱类型很多读者应该对动态类型和静态类型比较熟悉,但是很多人也会将它们与强类型和弱类型混淆,所以我们需要先做一个概念上的澄清。两组类型都特定于编程语言,但它们侧重于不同的核心问题。关于“动态类型和静态类型”的概念,其核心问题是“什么时候知道一个变量是什么类型?”一般来说,在编译时确定变量类型的语言是静态类型语言,而在运行时确定变量类型的语言是动态类型语言。比如在某些语言中定义了函数“intfunc(inta){...}”,在编译时就可以确定它的参数和返回值都是int类型的,所以它是一个static类型;而典型的函数如Python,当定义一个函数时写“deffunc(a):...”,你并不知道参数和返回值的类型。只有在运行时调用函数,才能最终确定参数和返回值的类型,所以对于“强弱类型”的概念来说,它是动态类型。它的核心问题是“不同类型的变量是否允许隐式转换”?一般来说,编译器有很少(合理)隐式类型转换的是强类型语言,有较多(过度)隐式类型转换的是弱类型语言。比如Javascript中的“1000”+1会得到字符串“10001”,而“1000”-1会得到数字999,也就是说编译器会根据使用场合做两种不同类型的对象。隐式类型转换,但是类似的写法在强类型语言中会报类型错误。(数字和字符串的转换属于过度转换,下面会讲到一些合理的转换。)根据上面的定义,有人画了一个常见编程语言的分类图:按强度和类型维度划分,可以总结输出:强类型:Java,C#,Python,Ruby,Erlang(plusGO,Rust)...弱类型:C,C++,Javascript,Perl,PHP,VB...2.强类型和弱类型的概念past这个概念大家基本都认同。然而,强类型和弱类型的概念在问答社区、技术论坛和学术讨论中存在很多争议。这里就不一一列举了。为什么会有这么多争议?主要原因之一是有些人将其与动态和静态类型混合使用。最明显的例子是GuidovanRossum在2003年参加的一次采访,主题恰好是关于Strong与WeakTyping的:然而,他们谈论的显然只是静态类型和动态类型之间的区别。采访中还引用了Java之父JamesGosling的话。从他的表述中也可以看出,他所说的“强弱类型”其实就是动态类型和静态类型的区分。还有一个经典的例子。C语言之父DennisRitchie曾说过C语言是一种“强类型但弱检查”的语言。如果和前面的定义相比,他其实指的是“statictypeweaktype”。为什么这些大佬都糊涂了?其实原因也很简单,就是当时没有明确的动态类型和静态类型,强弱类型的概念!也就是说,当时的强弱类型指的是动态类型和静态类型。维基百科在1970年代给出了强类型的定义,基本上可以简化为上面提到的静态类型:1974年,Liskov和Zilles将强类型语言定义为“每当一个对象从调用函数传递给一个被调用的函数,它的类型必须与被调用函数中声明的类型兼容。”[3]1977年,Jackson写道,“在强类型语言中,每个数据区域都有一个不同的类型,每个进程都会说明它的通信要求就这些类型而言。”[4]以前的编程语言之父应该持有类似的概念。不过老板们也意识到当时“强类型和弱类型”的概念不够准确,所以DennisRitchie说“强类型但弱检查”,而Guido在采访中也强调不应该使用Python叫弱类型,但应该说是运行时类型(runtimetyping)。但在那些早期,强类型和弱类型基本上是动态类型和静态类型的代名词,这种思想至今仍然影响着很多人。3.当前强弱类型的概念。早期的编程语言分类实际上是混合了动态和静态和强弱两个维度。但是,它们并不是一一对应的重叠关系,不足以表达编程语言之间的差异。因此,它需要一个更清晰/更丰富的定义。有人提出了“类型安全”、“内存安全”等区分维度,也出现了静态检查类型和动态检查类型,它们与强类型和弱类型有一定的交集。直到2004年出现了一篇综合性的学术论文《Type Systems》(来自微软研究院,作者LucaCardelli),专门研究编程语言的不同类型系统:有一篇简短的总结如下:Stronglycheckedlanguage:Alanguagewhere运行时不会出现禁止错误(取决于禁止错误的定义)。弱检查语言:经过静态检查但不提供不存在执行错误的明确保证的语言。关键是程序对未捕获错误的检查强度。有些实际已经出错的地方,弱类型的程序并没有捕捉到,比如C语言中的一些指针计算和转换,《C 程序员十诫》的前几个就是弱类型的问题。论文对这些概念的定义还比较抽象。由于大多数未捕获的错误都是由隐式类型转换引起的,因此第一节的定义有所演变,以隐式类型转换作为判断标准。如今,“对隐式类型转换的容忍度”作为强弱类型的分类标准,是很多人的共识(虽然不够全面,也有一些不同的声音)。例如,维基百科将隐式类型转换视为弱类型的主要特征之一:弱类型语言具有更宽松的类型规则,可能会产生不可预测的结果或可能在运行时执行隐式类型转换。比如以Python为例,社区主流观点认为它是强类型语言,判断标准也是基于隐式类型转换。例子很多,比如Python的官方wiki,专门回答了WhyisPythonadynamiclanguageandalsoastronglytypedlanguage,并给出了4个回答来刻画Python的“动态强类型”:又如,在《流畅的Python》杂项中talk在第11章中,也特别提到了强弱类型的分类。(它的术语是“很少隐式类型转换”,比较严谨,但也错误地将C++归类为强类型。)4.Python是强类型语言吗?关于“Python是不是强类型”这个话题,除了主流观点之外,还有很多被误解的观点。一方面,有些人将强类型和弱类型与动态类型和静态类型混合使用。这是有历史原因的,前面已经分析过了。还有一个同样重要的原因,就是有人把弱类型等同于“根本没有隐式类型转换”,这是错误的。事实上,强弱类型的概念包含了一些相对主义的含义,在强类型语言中也可能存在隐式类型转换。例如,为了实现“内存安全”的设计理念,Rust语言设计了非常强大的类型系统,但它也有隐式类型转换(自动解引用)。问题是:什么样的隐式类型转换是在合理范围内的?还有,一些表面上的隐式类型转换是否真的是隐式类型转换?回到Python的例子,我们可以分析几个典型的用法。比如“test”*3字符串“乘法”运算,虽然是两种运算,但不涉及隐式类型转换。例如,x=10;x="test"将不同类型的值依次赋值给一个变量。从表面上看,x的类型发生了变化。可以用type(x)来判断区别。但是,Python中的类型是绑定到值(右值绑定)而不是绑定到变量。变量x恰恰只是变量名,是绑定到实际变量的标签,它没有类型。type(x)判断的不是x本身的类型,而是x指向的对象的类型,就像内置函数id(x)计算的不是x本身的地址,而是x指向的对象的地址实际对象。比如1+True这样的数字加到Boolean类型上,是没有隐式类型转换的。因为Python中的布尔类型其实是整数类型的子类,是同一个类型!(如果你有疑问,可以参考PEP-285)例如,将一个整数/布尔值添加到一个浮点数不需要进行显式类型转换。但是,它的实现过程实际上使用了数字的__add__()方法。Python中的一切都是对象,数字对象也有自己的方法。(其他语言不一定)也就是说,数字之间的算术运算实际上是一个函数调用的过程,这与其他语言中的算术运算有本质区别。另外,虽然不同的数字类型在计算机存储层面上差别很大,但在人眼中,它们是同一种类型(大体上划分),所以即使发生隐式类型转换,逻辑上也是可以接受的。最后再举一个例子,就是Python在if/while之后的真值判断。之前分析过它的实现原理,它会将其他类型的对象转换成布尔值。但实际上只是函数调用的结果(__bool__()和__len__()),是通过计算得到的合理结果,不属于隐式强制转换,不属于未捕获错误的范畴。所以,严格来说,前面5个例子都没有发生类型转换。浮点数和真值判断的例子,直观上看是类型转换,其实是Python的特性,是可控的、预期的,不会对原有类型造成破坏。退一步讲,如果把“隐式类型转换”的含义放宽一点,上两个例子都认为发生了隐式类型转换,但它们是通过严格的函数调用过程实现的,不会出现禁止错误,所以他们仍然属于Stronglycheck类型。5.其他相关问题上一篇文章对概念的含义及其在Python中的表现做了详细的分析。接下来,为了逻辑和题目的完整性,我们还需要回答几个小问题:(1)“隐式类型转换”能否作为强弱类型的分类依据?清晰的分类定义应该是根据《Type Systems》准确的说,它对不同的错误都有一套分类,强弱类型其实就是对禁止错误的处理分类。隐式类型转换是其明显的特征,但不是全部,也不是判断的唯一依据。为了便于理解,本文以这个主要特征来区分强类型和弱类型,但必须强调的是,强类型并非没有隐式类型转换,只是隐式类型转换可能很少且合理。(2)如果有其他解释器让Python能够支持大范围的隐式类型转换,Python还是强类型语言吗?语言的标准规范就像一部法律,解释者就是执行者。执法解释错误,法律还是那个法律,错误的执法行为要纠正;如果法则本身有问题(造成解释上的歧义和矛盾,或者应该被丢弃),那么就应该修改法则以确保其确定性(强类型或弱类型)。(3)为什么Javascript是弱类型?因为它有很多隐式类型转换,很复杂,也很过分!比如Javascript中123+null的结果是123,123+{}的结果就是字符串“123[objectObject]”。另外,它的双等号“==”除了基本的比较操作外,还可能进行多次隐式类型转换。比如true==['2']判断的结果为假,而true==['1']为真,[]==![]和[undefined]==false的结果都是真...(4)C++是弱类型语言吗?上面说了,C++会用在《流畅的Python》是强类型,而实际上应该是弱类型。C++类型转换是一个非常复杂的话题。@庆雨楼小姐曾写过系列文章进行系统的探讨。文章地址为:HowtoovercomethecomplextypeconversioninC++?,详解C++的隐式类型转换和函数重构Load!,谁说C++的强制类型转换难懂?6.总结强弱类型的概念在网上有很多争议,不仅在Python,在C/C++等语言中也是如此。事实上,在学术上,这个概念早已被明确界定,而且事实上已经被很多人所接受。那些反对的声音大多是概念混用,因为他们忽略了语言分类的另一个维度;同时,也有一些值得注意的原因,就是强类型不能等同于“根本没有隐式类型转换”或者“只要没有xxx隐式类型转换”。本文介绍了Python在社区的主流分类,同时分析了几个疑似隐式类型转换的用法,证明了它是一门强类型语言。作者简介猫下豌豆花,广东人,毕业于武汉大学,现为苏飘程序员。他有一些极客思维,有一些人文情怀,有温度,有态度。本文转载自微信公众号“蟒猫”,可通过以下二维码关注。转载本文请联系Python猫公众号。
