强类型、弱类型、动态语言、静态语言、动态类型语言、静态类型语言之Python初探

/ 1评 / 0

最近在看Python,看到说Python是强类型语言,感觉有点奇怪,在我的印象中,Python作为动态类型的脚本语言,想当然就是弱类型了,找了下相关的文章,发现自己对这一块的理解是有些偏差的,对于这几个概念根本就没有搞清楚,搜集了点资料在此整理下。 

首先Python属于:强类型、动态类型的解释型语言,有点绕哈,再来看下具体的定义。

编译型语言和解释型语言

编译型语言(Compiled language)需通过编译器(compiler)将源代码编译成机器码,之后才能执行的语言。一般需经过编译(compile)、链接(linker)这两个步骤。编译是把源代码编译成机器码,链接是把各个模块的机器码和依赖库串连起来生成可执行文件。代表语言有C、C++、Pascal、Object-C、swift等

解释型语言(Interpreted language):将代码一句一句直接运行,不需要像编译语言一样,经过编译器先行编译为机器码,之后再运行。这种编程语言需要利用解释器,在运行期,动态将代码逐句解释(interpret)为机器码,或是已经预先编译为机器码的的子程序,之后再运行。代表语言有Python、PHP、Javscript、Ruby等

注意,Java和C#属于混合型,先将代码编译为字节码(bytecode),在运行时再进行解释。

静态语言和动态语言

这两个概念容易与静态类型语言和动态类型语言搞混,需要特别注意,有些资料也将他们混为一谈,误导读者。

静态语言(Static Programming Language):与动态语言相对应的,运行时结构不可变的语言就是静态语言。代表语言有Java、C、C++等

动态语言(Dynamic Programming Language): 是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。代表语言有Object-C、C#、JavaScript、PHP、Python、Erlang

静态类型语言和动态类型语言

静态类型语言(Dynamically Typed Language):与动态类型语言刚好相反,它的数据类型检查发生在在编译阶段,也就是说在写程序时要声明变量的数据类型。代表语言有C、C++、C#、Java、Object-C等

动态类型语言(Statically Typed Language)是指在运行期间才去做数据类型检查的语言。在用动态语言编程时,不用给变量指定数据类型,该语言会在你第一次赋值给变量时,在内部将数据类型记录下来。代表语言有Python、Ruby、Erlang、JavaScript、swift、PHP、Perl等

强类型语言和弱类型语言

这两个概念也是容易跟动静态类型语言搞混的,他们之前也没有必然联系

强类型语言 (strongly typed language):一旦一个变量被指定了某个数据类型,如果不经过强制类型转换,那么它就永远是这个数据类型。你不能把一个整形变量当成一个字符串来处理。代表语言有Java、C#、Python、Object-C、Ruby

弱类型语言(weakly typed language):数据类型可以被忽略,一个变量可以赋不同数据类型的值。一旦给一个整型变量a赋一个字符串值,那么a就变成字符类型。代表语言有JavaScript、PHP

 

理清了这些基本概念后,再来看下Python与同是动态类型但是弱类型的JavaScript的区别。

JavaScript执行结果
Python执行结果

从执行结果可以看到,JavaScript会自动类型转换,而Python则报TypeError,这也是强类型与弱类型的区别。

在Python中,一切皆对象,像整型、字符串等也都一样是对象,Python中变量是没有类型,变量赋值其实就是引用绑定。其引用的对象实例是有类型的从而决定变量的类型。

看Python的基本类型的时候立马就想到了Java的包装类,对比一下也能加深这一块的理解。

先看这一段Java代码

public class Main {

    public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        System.out.println(a == b);
        System.out.println(a.equals(b));
        Integer c = 1000;
        Integer d = 1000;
        System.out.println(c == d);
        System.out.println(c.equals(d));
    }
}

其执行结果如下:    

在Java中==用于判断是否是同一个实例,equals则用于判断值是否相等。

观察其执行结果,会觉得有点奇怪,为什么c==d返回的false而a==b返回的事true?要知道为什么,需要了解Java的常量池,这里不做深入的说明,具体可以参考:Java常量池理解与总结

其实在Python也有同样的情况,不过在Python中 == 表示值相等,用 is 来判断是否是同一个实例,来看下面一段代码

其结果其实跟Java运行的一样,也就是说,Python中也有常量池这个概念。

出于对性能的考虑,Python内部做了很多的优化工作,对于整数对象,Python把一些频繁使用的整数对象缓存起来,保存到一个叫small_ints的链表中,在Python的整个生命周期内,任何需要引用这些整数对象的地方,都不再重新创建新的对象,而是直接引用缓存中的对象。Python把这些可能频繁使用的整数对象规定在范围[-5, 256]之间的小对象放在small_ints中,但凡是需要用些小整数时,就从这里面取,不再去临时创建新的对象。因为1000不在小整数范围内,因此尽管c和d的值是一样,但是他们在Python内部却是以两个独立的对象存在的。

弄明白了上边这个问题后,在来看下边的代码
   

为了弄清楚这个问题,我们有必要先理解程序代码块的概念。Python程序由代码块构成,代码块作为程序的一个最小基本单位来执行。一个模块文件、一个函数体、一个类、交互式命令中的单行代码都叫做一个代码块。在上面这段代码中,由两个代码块构成,c = 1000作为一个代码块,函数foo作为另外一个代码块。Python内部为了将性能进一步的提高,凡是在一个代码块中创建的整数对象,如果存在一个值与其相同的对象于该代码块中了,那么就直接引用,否则创建一个新的对象出来。Python出于对性能的考虑,但凡是不可变对象,在同一个代码块中的对象,只有是值相同的对象,就不会重复创建,而是直接引用已经存在的对象。因此,不仅是整数对象,还有字符串对象也遵循同样的原则。所以 a is b就理所当然的返回True了,而c和a不在同一个代码块中,因此在Python内部创建了两个值都是1000的对象。

 

 

参考资料:

http://www.cnblogs.com/zy1987/p/3784753.html

https://foofish.net/python-int-mystery.html

一条回应:“强类型、弱类型、动态语言、静态语言、动态类型语言、静态类型语言之Python初探”

  1. 说道:

    hahahhahahhahahahahaha

发表评论

电子邮件地址不会被公开。 必填项已用*标注