python基础学习-按值传递和按引用传递

按值传递和按引用传递在java和以c++中很常见,Java对待对象是按引用传递和,对待基本数据类型是按值传递的。

这里一定要注意java的String,因为java的String虽然是一个类,但是如果直接写成String str0="abc"的话,这里的str其实是指向常量池中的一个字符串,整个常量池只会有一个“abc”,如果再写一个str1="abc"的话,str0和str1其实是指向的同一个对象,所以str0==str1是true的,但是如果如果是String str2 = new String("abc")的话,就是在堆栈中申请的一块内存,这时候的str2就是指向的这块内存了。

扯远了,还是扯回python的按值传递和按引用传递上来。其实python也跟Java差不多,但是在python中万物皆对象,其中基本数据类型的实例也是对象,但却存在着可变数据类型和不可变数据类型,也可以称为动态和非动态的。

比如列表,集合,字典就是动态的,如果往其实添加或删除某些元素,引用指向的内存其实是不会变的,也就是说还是那个对象,但是如果是非动态和数据实例的话,就会重新申请一块内存了。这个问题用C++比如好说明,在C++中除了基本数据类型外,structure结构体类型也是非动态的。下面就用IDLE写一下程序来验证一下。

Python 2.7.13 (default, Jan 19 2017, 14:48:08) 
[GCC 6.3.0 20170118] on linux2
Type "copyright", "credits" or "license()" for more information.
>>> a = 1
>>> b = 1
>>> a==b
True

这段代码,很明显,在其他语言中也是这样的。

>>> a = "abc"
>>> b = "abc"
>>> a==b
True

嗯,这段代码,也很容易懂为什么要True

接下来,我们来试试动态的数据类型实例

>>> a.append(1)
>>> a
[1, 2, 3, 1]
>>> b
[1, 2, 3]

其实还是比较容易理解的。

那就来试试在函数中的参数传递问题

>>> a = 1
>>> def test(x):
x = x+1
return x


>>> b = test(a)
>>> b
2
>>> a
1
从这里可以看出对于int这种基本数据类型,在函数参数的传递中是按值传递的

>>> t0 = (1,2,3)
>>> def test(t):
t = (2,3,4)


>>> t0
(1, 2, 3)
>>> test(t0)
>>> t0
(1, 2, 3)
>>> 

这里可以看出,像元组这种数据类型其实跟基本数据类型一样,也是按值传递的。

那让我们再来看看按引用传递的情形

>>> l0 = [1,2,3,4]
>>> del test
>>> def test(l):
l[0] = 10



>>> l0
[1, 2, 3, 4]
>>> test(l0)
>>> l0
[10, 2, 3, 4]

从这里的结果就很明显可以看出差别了吧,其实就是这样的。

python是不直接提供定义结构体的,但可以通过numpy模块来定义结构体

那自定义的类型呢

>>> class MyClass:
number = 0
def __init__(self,number):
self.number = number



>>> c = MyClass(10)
>>> c
<__main__.MyClass instance at 0x7f876b7fa248>
>>> print str(c)
<__main__.MyClass instance at 0x7f876b7fa248>
>>> c.number
10
>>> del test
>>> def test0(arg):
arg = MyClass(5)



>>> test0(c)
>>> c.number
10

这里我们先做的一个实验是验证自定义的类型在函数参数传递时,传递的参数是按什么传递的,结果很明显,参数是按值传递的,很好理解,其实python的函数把参数名当成一个基本数据类型,向底层理解其实就是一个指向这个MyClass对象的一个指针,而指针是什么类型的呢,通常指针是被定义成一个地址的,这个地址保存的是这个对象的起始内存地址编号和终结内存地址编号(现在的计算机架构把内存做成的是一个线性的)所以这个实验中,即使在test函数中让arg指向了另一个对象,但是其实是没有改变外部变量指向的真实地址的,我实验过,在java和以c++也是如果,不过以c++可能比较灵活,提供了一个&符号来取地址,如果不用&的话就和python和java一样了(在此不得不佩服c++,虽然麻烦了点,我们写程序时要时刻注意着内存的问题,但是如果代码能力提上去了,写出的代码真的比java舒爽多了)。

其实这里很多人都没有去理解过或者没有重视过,我以前半夜给同学调bug的时候就发现好多同学就是这个没有注意程序老是出问题,我当时真的很无语,真的是哭笑不得。


我们再来看看如果是在函数中改变对象的成员的值会怎么样

>>> def test1(arg):
arg.number = 5



>>> c
<__main__.MyClass instance at 0x7f876b7fa248>
>>> c.number
10
>>> test1(c)
>>> c.number
5

嗯,如想象的一样,原因在上面已经说过了。

按值传递按引用传递的问题,是初级程序员经常犯的错误,在大一的时候经常因为没了理解透这方面的问题,自己也没有重视这个问题,程序经常出现很奇怪的bug,自己调了半天也不知道到底是怎么回事,当时真的是特别二。





你可能感兴趣的:(python,学习)