浅析Python与Java和C之间有哪些细微区别
作者:小嗷犬
1.变量是什么
(1)C认为变量应该是容器
传统的观点通常将变量比喻成容器,不同类型的容器储存不同的物质,就如同不同数据类型的变量存储不同类型的值一样。
人们用杯子装水,用篮子装菜,这一切都是这么正常。
C也是这样认为的,它认为变量就和这些容器一样,int类型的杯子就不能装double类型的菜,float类型的篮子就不能装char类型的水。
它也是这样做的,在C程序中,将不匹配的值赋值给变量是不合法的,这些值有的会被隐式转换,有的干脆就办不了,程序直接撂挑子不干了。
所以C中的变量分别鲜明,各尽其责,所有变量的空间在诞生时就被分配好,未来将要存储的数据也被注定。
#include <stdio.h> int main() { int a = 10; float b = 3.14; char c = 'm'; printf("a:%d, b:%f, c:%c", a, b, c); return 0; }
(2)Python认为变量应该是标签
Python并不认同以往的观点,它觉得传统的观点太刻板了,一个变量的未来不应该在它诞生之际就被限定死了,如同印度的种姓制度一样。
Python主张各变量之间的平等,变量可以存储任何类型的数据,Python也确实是这么做的。
a = 10 print(a) a = 3.14 print(a) a = "Hello World!" print(a)
但一旦认为是变量存储数据后,存储空间的分配又成了困扰Python的难题,一向平等的它不知道该按照什么标准去分配空间,变量们将要存储的数据类型还未可知,如果现在平均分配空间必然会导致今后的一些问题。
Python冥思苦想,终于有一天它想出了一个神奇的构想,它不必将数据需要的空间分配给变量,它只用给变量留足存储自己的空间,而数据则单独找它认领空间,然后将数据空间的地址交给变量保管。这样一个完全不一样的分配制度和所有制度就出现了。
// C中的空间地址是与变量绑定的 #include <stdio.h> int main() { int a = 10; int b = 10; printf("int型变量a的值为%d,地址为%p\n", a, &a); printf("int型变量b的值为%d,地址为%p\n", b, &b); a += 10; b += 10; printf("变化后变量a的值为%d,地址为%p\n", a, &a); printf("变化后变量b的值为%d,地址为%p\n", b, &b); return 0; }
# Python中的空间地址是与值绑定的 a = 10 b = 10 print(f"变量a的值为{a},地址为{id(a)}") print(f"变量b的值为{b},地址为{id(b)}") a += 10 b += 10 print(f"变化后变量a的值为{a},地址为{id(a)}") print(f"变化后变量b的值为{b},地址为{id(b)}")
(3)Java认为我们不应该关心这个问题
Java打造了一台功能强大的虚拟机,即所谓的JVM,来帮我们解决包括存储空间分配在内的内存管理问题,涉及到内存的操作都由JVM来完成,程序员不用也不能直接操作内存。
Java担心我们不能合理分配利用空间,所以它用自己的方法解决了这个问题。
2.循环与迭代
(1)传统的循环
C是三者中最年长的语言,它的循环也很具有代表性,循环结构是用来处理一系列相似的事物的,这种重复劳动是十分无趣的,所以C通常是数着数来统计重复的次数,然后看看什么时候能下班。
它使用一种自增运算来数数,用一个整型变量来存储次数,为了方便逐个的自增,它发明了i++和++i这种结构来简化命令,这样的运算也被后来的许多语言效仿。
#include <stdio.h> int main() { for (int i = 0; i < 10; i++)//经典的i++自增 { printf("%d\n", i); } return 0; }
(2)继承与发展
Java也是一位比较老的语言,但它的资历没有C老,自身习惯上也受到C很大的影响,循环就是其中之一,C语言中的循环在它这里也能使用。
但它后来就发现了问题,传统的循环要在知道该重复多少次的时候才能按时结束,对于成堆的任务,Java有时候很难事先知道它们有多少。
Java后来发现,是它考虑的太多了,它根本没必要知道要做多少,甚至没必要统计自己现在做了多少了,对于固定量的任务,它只要让循环把它们都做完就行了,没有做完就继续做,做完了就可以提前下班。
于是Java规定了一个新的循环规则,即迭代循环。
public class Main { public static void main(String[] args) { int[] numbers = { 5, 3, 8, 4, 6, 1, 7, 2 }; //迭代循环 for (int item : numbers) { System.out.println(item); } } }
这样的循环似乎并不比传统循环更难使用,但那时候的大多数语言还是以传统循环为主,包括我们的Java。
(3)新的问题
在其他语言使用传统循环解决问题时,Python似乎有点愁眉苦脸,它又遇到了新的问题。
在之前对变量处理中,Python选择为值分配内存空间,而不是传统的只为变量分配空间。在进行重复工作时,工作的计数器会不断产生新的值,Python要为这些产生的新值都分配空间,在少量的重复工作时,Python感觉还能吃得消,但量级一大,Python就没有这么多空间可以分配了。
按照这种分配方式,计数器的每一次++自增都会产生一个新值,都需要为它分配内存空间,如果循环重复100次,它就要消耗100个数据单位的空间,如果重复1000次呢?10000次呢?Python不敢往下想了,问题迫在眉睫。
Python翻阅古籍,终于找到了以前Java发明的一种不同的循环方式,这就是它要找的解决问题的答案。它发明了一个迭代器range来取代之前的自增计数器,迭代器里的数只有在取用的时候才占据内存,使用完将会在循环结束后释放,这样一来就能解决内存空间的问题了。
# Python迭代循环打印0到9 for i in range(10): print(i)
// C语言传统循环打印0到9 #include <stdio.h> int main() { for (int i = 0; i < 10; i++) { printf("%d\n", i); } return 0; }
实验结果正如同Python想的那样,内存空间的无谓损失被降低了。
为了推广这个新的循环方式,它禁用了传统循环,并废除了i++或是++i自增的用法,鼓励大家使用迭代器range搭配新的循环。
3.尾声
(1)万物皆对象
三者中最先提到类与对象这个概念的是我们的Java,它认为万物皆是类,包括它自己,从此面向对象编程横空出世,但它还要兼容传统的思想,对此它的JVM对传统的基本数据类型和新的类对象做了不同处理。
对于传统的基本数据类型,JVM将其存在栈中,而将实例化的对象存在堆中。在函数调用时,对于简单的基本数据类型,JVM进行值传递,而对于复杂的对象则采用引用传递。
相应的变量在相互赋值的时候,有的对象会不幸失去引用,如果没有变量引用它,它将变得无法操作,它的存在将没有意义。Java很贴心地安排了JVM去回收它们,这样的回收系统同样也可以用来回收那些不会再被用到的数据。
虽然看起来Java对它们有些不尽人情,用完不需要别人了就回收,但这一切都是为了计算机更好的执行任务。
(2)C的自增
为了更好的适应新的任务,C也学着Java加入了类与对象的功能,C实现了自身的进化,进化成了C++,它在利用类与对象的便利的同时,并不承认万物皆对象的观点,这也让它保存了C那时面向过程编程的风格。
C++封装了许多常用类来方便我们工作,同时允许我们直接操作内存,没有像JVM虚拟机那样的阻隔,保持着C语言原有的高速,同时更加接近底层。
(3)Python的好名声
Python是三者中诞生最晚的,它最开始是没有什么知名度的,在C与Java面前只能老老实实当小弟。但年轻人还是不一样,它敢想敢做,首先是实现了各变量之间的平等,让它们能够存储任意数据,然后解决了内存空间的相关问题。
除此之外,它开源自己,广泛吸取大家的意见,Python逐渐变得知名了。
在这些过程中,Python不断改善自身,变得十分人性化,简单的语法、便捷的方法,都吸引着其他程序员去了解,程序员们也能很容易的入门。
现在,Python除了自带的标准库外,支持导入很多的外部库,大大地拓展了Python的应用范围。这一切都仰仗它一直以来的好名声,使得不断有人前赴后继贡献自己的便捷方法,为其编写外部库。
现在Python虽然没有C/C++那样的速度,但是它的便捷性已经不输其他老一辈的语言了,程序员们在写小程序的时候会更加青睐它。
到此这篇关于浅析Python与Java和C之间有哪些细微区别的文章就介绍到这了,更多相关Python Java C语言区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!