平时学习使用的语言较多是C++,Python平时一般是用来简单掉包、数据分析使用的,但最近面试发现,用C++做笔试题又慢又繁琐,朋友用Python做的比我快多了(也可能因为算法实在太菜了/哭),故写该博客记录C++与Python的不同点,方便自己复习回顾。
说明:
- 本文适合对C++和Python都用了解的朋友;
- 慢慢更新ing;
- 博主也是菜鸟一枚,有错误希望大家严厉批评。
1.全局变量
在C++中,main函数内的变量不是全局变量,而是局部变量,只不过它的生命周期和全局变量一样长而已,而全局变量一定是定义在函数外部的。
在Python中,main函数中的变量默认为全局变量,而其他的def函数中的变量则默认为局部变量。
2.变量作用域
在C++和Python中,全局变量和局部变量用同一个名字,内层都会屏蔽外层。
int n = 1;
int main()
{
int n = 4;
cout << n ;
}
4
>>> a = 3
>>> def f():
... a = 5
... print(a ** 2)
...
>>> f()
25
>>> a
3
而在Python中有globel语句强制使局部变量转为全局变量,但一般不推荐使用:
>>> def f(x):
... print(m)
... m = 5
... print(m + x)
...
>>> m = 3
>>> f(8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f
UnboundLocalError: local variable 'm' referenced before assignment
>>> def f(x):
... global m
... print(m)
... m = 5
... print(m + x)
...
>>> m = 3
>>> f(8)
3
13
>>> print(m)
5
3.使用函数
在C++中,调用非inline函数会将更多的东西入栈,进而在函数返回时为程序带来负担,但一般为了增强可读性,还是会选择使用函数,当然效率的降低一般可以忽略。
但在Python中,如果只是把所有代码扔进一个文件而没有把它们放进函数,那么它会因为众多的全局变量而变慢。因此,可以通过将所有代码封装、在 main函数中并调用来实现加速。
4.传址还是传值?
Python是不允许程序员选择采用传值还是传址的。Python参数传递采用的是“传对象引用”的方式,实际上,这种方式相当于传值和传址的一种综合。
如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于传址。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于传值。所以python的传值和传址是根据传入参数的类型来选择的.
定义函数:
def f(l):
l[0] = 1
测试列表:
l = [0,1,2]
f(l)
print(l[0])
1
测试元组:
t = (0,1,2)
f(t)
print(t[0])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-b8e76a0aa5a1> in <module>
1 t = (0,1,2)
----> 2 f(t)
3 print(t[0])
<ipython-input-2-4b9a0ca3ec49> in f(l)
1 def f(l):
----> 2 l[0] = 1
TypeError: 'tuple' object does not support item assignment
测试自定义对象:
class A:
x = 1
a = A()
def fclass(a):
a.x = 2
fclass(a)
print(a.x)
2
测试基本类型:
def fb(x):
x = 3
x = 1
fb(x)
print(x)
1
故可以进行总结:
- 对于基本类型,函数为传值,可通过返回值获取变化后的量;
- 对于列表、字典、自定义类型等可变对象,可以理解为传址操作;
- 数字,字符串,元组等不可变对象,可以理解为传值操作。
5.浅拷贝还是深拷贝?
注:在python中可以用id()函数获取对象的内存地址。
测试基本数据类型:
a = 5;
b = a;
a = 6;
print(a,b)
print(id(a),id(b))
6 5
140707683383232 140707683383200
一般基本数据类型不涉及深浅拷贝问题,这里主要为了与下面对比。
测试自定义数据类型:
class A:
def __init__(self, x):
self.x = x
a = A(5)
b = a
a.x = 6
print(a.x, b.x)
b.x = 6
print(a.x, b.x)
print(id(a.x), id(b.x))
6 6
6 6
140707683383232 140707683383232
可以看出,自定义类型的拷贝只是个引用而已。
测试可变对象:
a = [1,2,3,4]
b = a
a[0] = 5
print(a[0],b[0])
b[0] = 6
print(a[0],b[0])
print(id(a),id(b))
5 5
6 6
2069683308416 2069683308416
可以看出,可变对象的拷贝也只是个引用而已。
测试不可变对象:
a = (1,2,3,4)
b = a
print(a[0],b[0])
print(id(a),id(b))
1 1
2069683361968 2069683361968
可以看出,不可变对象的拷贝也只是个引用而已,而且不可变对象引用是一件比较自然的事。
可以看到Python对拷贝这件事和C++的思路差别比较大,但我们想深拷贝怎么办?此时需要调用deepcopy进行深拷贝:
import copy
a = [1,2,3,4]
b=copy.deepcopy(a)
a[0] = 5
print(a[0],b[0])
b[0] = 6
print(a[0],b[0])
print(id(a),id(b))
5 1
5 6
2069683316352 2069682746112