作者:子恒
这个感悟是在做一道题中产生的,题目其实很简单,如下:
下列两个组代码分别输出的结果是什么?
def num_value(num1): num1 = 2 num1 = 1 num_value(num1) print(num1)
def num_value(num1): global num1 num1 = 2 num1 = 1 num_value(num1) print(num1)
我最初的答案是:2,2
然而正确答案是:1,2
复盘一下我做这道题时候的错误思考:
- 第一组代码:给
num1
赋值1
,随后进入函数num_value
中,给num1
改变赋值为2
,跳出函数,输出num1
结果为2
- 第二组代码:和第一组代码相同,
global
声明num1
为全局变量没有意义
看了正确答案之后我格外懵逼,我不明白第一组代码为什么明明在函数内num1
的赋值变为了2
但是程序输出的结果却是1。于是我把题目和我的疑惑发到python学习群里,有人建议我在函数内num1 = 2
之前和之后都加上print(num1)
之后再运行一下程序看看。代码如下:
def num_value(num1):
print(num1)
num1 = 2
print(num1)
num1 = 1
num_value(num1)
print(num1)
输出结果如下:
1
2
1
前两个结果在函数内的输出结果,如我所料,可是奇怪的是赋值完毕跳出函数的时候num1
又神奇的变回了1
!
后来群里的人提到了传值和传址并且发给我了一个解释这个原因的文章链接:
【详解python函数传参是传值还是传引用】文章中全都是这样的论述:
Python参数传递采用的是“传对象引用”的方式。这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值,相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象--相当于通过“传值'来传递对象。
文章过于专业,反而整的更深奥了。我思考之后是这么理解的:
- 函数外部
num1 = 1
的1
作为实参传入函数内,函数内的num1
作为局部变量接收的1
则变为了形参来参与函数内的赋值、运算等操作。此时函数内的一切操作若没有以return
语句返回任何值给函数体,则意味着函数什么也没有做,即所谓的“一通操作0-3”。通俗的讲,函数内的num1
和函数外的num1
其实是两回事。函数里头num1
不管怎么赋值和变化,到了函数外该是什么还是什么。
于是我对题目内的第一组代码进行改写,以进行验证。
实验1:把函数num_value(num1)
赋值给函数外的num1
def num_value(num1):
print(num1)
num1 = 2
print(num1)
num1 = 1
num1 = num_value(num1)
print(num1)
实验1输出结果如下:
1
2
None
实验2:在函数内加入return num1
来返回函数内num1
的值,并把函数num_value(num1)
赋值给函数外的num1
def num_value(num1):
print(num1)
num1 = 2
print(num1)
return num1
num1 = 1
num1 = num_value(num1)
print(num1)
实验2输出结果如下:
1
2
2
两个实验证明了我的理解是对的,在第一个实验中,因为函数num_value(num1)
没有再函数内返回任何值出来,所以是一通毫无意义的操。此时把num_value(num1)
赋值给函数外的num1
,自然输出了None
。当我在函数内填入了返回值return num1
之后,再次运行程序的结果输出为2
。
至此,我对局部变量、全局变量、实参、形参有了一个更清晰而深刻的认识。
我想,函数相关知识是python初阶的重点难点,可能对于大多数人来说很简单的这样一道题如果我只是似懂非懂的放过去了(之前也做过一道类似的题,我也做错了,但是放过去了),那么真正到使用的时候会遇到更多的困惑,会写出更“魔幻”的代码。
学习编程是绝对的需要理论与实践紧密结合的。
听课看书之后以为自己懂了,十有八九上手时候问题百出;实践之后代码跑成了就认为自己会了,碰到原理问题,十有八九还是混混沌沌。前者纸上谈兵,根本无法胜任实际的编程工作。后者把写代码变成了看运气看命的玄学,并不能在行业内有长足的发展。
到处都是xx天编程速成的宣传文案,看着让人心动,其实何来速成,又哪里有捷径。
速成来的东西,终究还是不能长久。要想有更好的发展,也只有学习更多看似枯燥的基础知识,多练习、多自我延伸探究、多把过往知识横向连接。
一定要知其然且知其所以然。
网友评论