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

本文探讨了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中,函数参数的传递方式可以被认为是“对象引用传递”。这意味着当你将一个变量作为参数传递函数时,实际上传递的是该变量所引用的对象的引用(即内存地址),而不是对象的副本。 ### 值传递 vs. 引用传递 1. **值传递**: -值传递中,函数接收到的是实际参数的一个副本。对副本的修改不会影响原始数据。 - 例如,在C语言中,整数浮点数通常通过值传递。 2. **引用传递**: - 在引用传递中,函数接收到的是实际参数的引用(或地址)。对引用指向的对象的修改会影响原始数据。 - 例如,在C++中,可以通过指针实现引用传递。 ### Python中的“对象引用传递” 在Python中,所有变量都是对象的引用。因此,当你将一个变量传递函数时,你实际上是传递了该变量所引用的对象的引用。 #### 可变对象与不可变对象 - **不可变对象**(如整数、字符串、元组):这些对象一旦创建就不能被修改。如果你在函数内部尝试修改不可变对象,实际上是创建了一个新的对象,而原始对象保持不变。 - **可变对象**(如列表、字典、集合):这些对象可以在创建后被修改。如果你在函数内部修改可变对象,原始对象也会被修改。 ### 示例代码 ```python def modify_list(lst): lst.append(4) print("Inside function:", lst) my_list = [1, 2, 3] modify_list(my_list) print("Outside function:", my_list) ``` 输出: ``` Inside function: [1, 2, 3, 4] Outside function: [1, 2, 3, 4] ``` 在这个例子中,`my_list`是一个可变对象(列表)。当我们将其传递给`modify_list`函数时,函数内部的修改会影响到原始的`my_list`。 再看一个例子: ```python def modify_number(num): num += 10 print("Inside function:", num) my_number = 5 modify_number(my_number) print("Outside function:", my_number) ``` 输出: ``` Inside function: 15 Outside function: 5 ``` 在这个例子中,`my_number`是一个不可变对象(整数)。当我们将其传递给`modify_number`函数时,函数内部的修改不会影响到原始的`my_number`,因为整数是不可变的,函数内部的操作实际上是创建了一个新的整数对象。 ### 总结 - Python中的函数参数是通过对象引用传递的。 - 对于可变对象,函数内部的修改会影响到原始对象。 - 对于不可变对象,函数内部的修改不会影响到原始对象。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值