浅析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语言区别内容请搜索编程宝库以前的文章,希望以后支持编程宝库

1.对于一维数组,可以有:2. 对于二维数组:考虑可将其看作为矩阵,故可以如下书写二重遍历这里外层循环的是二维数组A的行,内层则是列同时c的作用:不想用肉眼直接观察得到行列数,故用A.shape方 ...