查看原文
其他

传值or传引用?一文明白Python的传参过程

爬虫俱乐部 Stata and Python数据分析 2022-03-15

Python

本文作者:徐露露

本文编辑:胡   婧

技术总编:张学人


好消息!!!爬虫俱乐部将于2018年11月30日2018年12月2日在武汉举行Stata编程技术培训。本次培训主要面向财务会计金融专业高校教师、硕博生,课程均是采用财务金融领域的案例,旨在帮助财务金融领域的研究者熟悉Stata数据分析技巧,能够通过编程读取不同类型的数据源、实现复杂数据合并、清洗的程序化,通过简单的程序构造复杂的财务金融指标。详细培训大纲及报名方式,请点击文末阅读原文呦~

爬虫俱乐部是您身边的科研助手,能够为您在数据处理实证研究中提供帮助。承蒙30000+粉丝的支持与厚爱,我们在腾讯课堂推出了网络视频课程,专注于数据整理、网络爬虫、循环命令编制和结果输出…李老师及团队精彩地讲解,深入浅出,注重案例与实战,让您更加快速高效地掌握Stata技巧及数据处理的精髓,而且可以无限次重复观看,百分百好评,简单易学,一个月让您从入门到精通。绝对物超所值!观看学习网址:https://ke.qq.com/course/286526?tuin=1b60b462,敬请关注!

有问题,不要怕!访问 

http://www.wuhanstring.com/uploads/5_aboutus/爬虫俱乐部-用户问题登记表.docx (复制到浏览器中)下载爬虫俱乐部用户问题登记表并按要求填写后发送至邮箱statatraining@163.com,我们会及时为您解答哟~

爬虫俱乐部的github主站正式上线了!我们的网站地址是:https://stata-club.github.io,粉丝们可以通过该网站访问过去的推文哟~

爬虫俱乐部隆重推出数据定制及处理业务,您有任何网页数据获取及处理方面的难题,请发邮件至我们邮箱statatraining@163.com,届时会有俱乐部高级会员为您排忧解难!

面试的时候,有没有被问到Python传参是传引用还是传值这种问题?有没有听到过Python传参既不是传值也不是传引用这种说法?其实在Python中讨论值传递还是引用传递是没有意义的,要真正对这些情况作出解释,其实是应该搞明白的是在Python对可变对象和不可变对象的赋值过程中,它是如何分配内存地址的。

比方说在实际操作过程中,我们遇到了如下问题:

l=[1,2,3]
def a(x):    x=x+[4]
   return x a(l) print(l)

运行之后,结果居然不是[1,2,3,4],而依旧是[1,2,3]。这是为什么呢?

万物皆对象

无论是一个数字、字符串,还是数组、字典等,在Python中都会以一个对象的形式存在,并在Python中有一个唯一的内存地址。Python中的对象分为两类:可变对象不可变对象。不可变对象指元组、字符串、数字等类型的对象,可变对象指的是字典、列表、自定义对象等类型的对象。举一个简单的例子,其中id()可以查看变量在内存中的地址:

list_1=[1,2,3] list_2=[1,2,3] a=1
b=1
print(id(list_1)) print(id(list_2)) print(id(a)) print(id(b))

得到:

这说明,对于可变对象列表来说,即便列表内容一样,Python也会给它们分配新的不同的地址。然而,对于不可变对象数字来说,内存里只有一个1。即便再定义一个变量c=1,也是指向内存中同一个1。换句话说,不可变对象1的地址是共享的。

此外,我们对可变对象list_1进行修改:

list_1=[1,2,3] print(id(list_1))
def a(x):    print(id(x))    x.pop()    print(x)    print(id(x))    x=x+[3]    print(x)    print(id(x)) a(list_1)

得到:

可以发现,当调用x自身的方法pop后,x变为[1,2],但对象本身的标识并不会发生变化,只有当我们给它重新赋值给x之后,x的地址才会发生改变。也就是说,只有创建一个新的可变对象,Python才会分配一个新的地址。就算我们创建的新可变对象和已存在的旧可变对象完全一样,Python依旧会分配一个新的地址。

所以回到我们最初遇到的那个问题,如果想要得到[1,2,3,4],我们可以这样写:

l=[1,2,3]
def a(x):    x=x+[4]
   return x l=a(l) print(l)

浅拷贝与深拷贝

在实际操作过程中,我本来想把修改前的a赋值给b,但是结果却发现b随着a的变化而发生了变化。

a = [1,2,3] b = a a.append(4) print(a,b) print(id(a),id(b))

通过查看它们在内存中的地址,我们可以发现,a,b指向的是同一个地址,这也就解释了为什么a,b同时变化。如果我们想生成的b是一个新的对象的话,就可以使用copy模块

import copy a = [1,2,3] b = copy.copy(a) a.append(4) print(a,b) print(id(a),id(b))

这说明采用copy方式会将对象拷贝一份到新的内存地址中。但copy和deepcopy有什么区别呢?接着往下实验:

a = [1,[1,2,3],3] b = copy.copy(a) a.append(4) a[1].append(4) print(a,b) print(id(a),id(b)) print(id(a[1]),id(b[1]))

通过观察,可以发现子对象a[1]和b[1]指向的依旧是同一个内存地址。这说明,copy.copy只拷贝父类对象,不会拷贝对象内部的子对象。

如果我们想要完完整整地拷贝,就可以使用copy.deepcopy

a = [1,[1,2,3],3] b = copy.deepcopy(a) a.append(4) a[1].append(4) print(a,b) print(id(a),id(b)) print(id(a[1]),id(b[1]))


对爬虫俱乐部的推文累计打赏超过1000元我们即可给您开具发票,发票类别为“咨询费”。用心做事,只为做您更贴心的小爬虫!

往期推文推荐

关于我们

微信公众号“爬虫俱乐部”分享实用的stata命令,欢迎转载、打赏。爬虫俱乐部是由李春涛教授领导下的研究生及本科生组成的大数据分析和数据挖掘团队。

此外,欢迎大家踊跃投稿,介绍一些关于stata的数据处理和分析技巧。

投稿邮箱:statatraining@163.com

投稿要求:
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。
2)邮件请注明投稿,邮件名称为“投稿+推文名称”。
3)应广大读者要求,现开通有偿问答服务,如果大家遇到关于stata分析数据的问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存