菜鸟级的Python函数解读,从而以一个电脑初级选手的视角来看待Python编程中的函数。或许作为一个菜鸟,很多地方的理解都是无厘头的,但目的是能够有助于我对它理解和有效掌握,我觉得还是有价值的。
为什么要有函数机制
我们其实可以思考,为什么我们文件多了,要建立文件夹?当然是为了更有序的对我们的文件进行管理。
同样,编程中的函数机制(甚至是以后更大的类、模块、包等概念)都是为了让数据更加有序,有利于程序数据的管理而产生的。
对比一下两种不同的方式:
第一种方式:
a = 4
b =3
c = a2+b2
d = 6
e = 8
f = d2+e2
print(f)
第二种
def gougu(c,d):
c = c2+d2
a = c/2
return c
print(gougu(3,4))
print(gougu(6,8))
所以,我们可以将函数就看作一个文件夹,把数据有效封装起来,以便对外没有干扰,保持自己功能的独立性和完整性,从而通过函数的机制让数据和数据的处理逻辑能够得到重复利用——这也是函数最大的价值所在——重复利用!
函数中的元素解构说明
def——通过这个标识符告诉Python,接下来的代码要“给我”放入一个“文件夹”里面保存起来,从而让下面的代码和外界独立。
gougu——是函数的名称,其实就是一堆组合在一起的代码段的地址而已。只不过我们记不住地址(一堆数据),而我们能记住一些有意义的英文字符串,因此,我们用一个名称来代替了一堆代码段的地址而已。
()——可以看做是元组,用来存放函数的参数用。如果我们将函数(在英文里面就是function,工厂的意思)看成一个工厂,那这个用来存放参数的()元组,其实就相当于工厂加工机器的原料进口。
:——在Python中表明接下来的代码段会归为冒号前的那个函数名称所代表的地址下。
接下来就是在冒号下编写代码了!
由此可见函数也可以看做是一个数据结构,而且是有一定结构和运行机制的数据结构(机制为——先定义、再调用)。
或者说,通过函数,我们能够将运算操作符(加减乘除)和基础数据类型(整数、字符串、元组、列表、集合、字典等)以各种方式组合起来,实现不同的功能。
这一点就像我们用钢铁加工成不同的零件,在将这些零件采用不同的组合,构成具有不同功能的机器一样。
函数的运行机制
其实,如果将函数看做一个去包括基础数据和操作符的文件夹,就不难理解函数的运行机制了。
就如同我们要使用(重复)一个文件或文件夹,实现你最起码要建立一个文件夹吧,然后才能通过复制、粘贴去重复使用一份文档或包含文档的文件夹,是不是。
函数也是这样,你想能够重复使用一个函数,最起码你首先要把这个函数定义出来。
相比使用,定义函数会更加有技术含量。因为你是在创造!
定义一个函数,包括给出关键词def (define),给出能够让你记住代码段放哪里了的函数名称(就像你要给一个文件夹命名一样,不然随着文件夹变多,你怎么找到你要的文件夹呢),接着需要思考给这个函数(工厂)放入哪些参数(原料)让它去加工,最后就是函数主体的代码块,即函数的功能实现代码(包括基础数据结构和相关的操作运算逻辑),小学四年级语文一对一辅导就好比工厂的机器有自己的加工流程(函数其实最像工程里面的机器,而类就像是一个车间——包括很多台机器和原料,模块则就相当于一个生产链条中的一个加工环节的工厂、包则就是整条生产链)。最后就是原料生产完成后,出来什么产品,而这个产品就是我们函数中的return来表达。
接下来就是函数的调用了,对Python来说,调用函数我觉得分为显性调用和隐性调用。看下面的代码
def gougu(c,d):
c = c2+d2
a = c/2
return c
print(gougu(3,4))#隐性调用,直接将函数名称写在了print中,没有任何显式变量指向这个gougu(3,4)
print(gougu(6,8))
i=gougu(2,4)#显式调用,用i这个内存变量指向了这个gougu(2,4)的函数地址
print(i)
函数的调用,其实可以理解为工厂中的机器启动,你只有给它通电了,机器的整个部件才会联动的运转起来。
类似的,i=gougu(2,4)就是用=去启动这台函数机器,也就是通过变量将函数的地址放入运行内存中,让计算机的CPU可以访问到这个函数,而一旦“通电”,通过函数的触发机制(trigger),函数就是自动运算起来。
而函数的这种触发机制,正是通过def这个标识符关键词告诉Python,接下来你遇到的地址gougu所代表的存储地址是需要自动触发运算的——即,它是函数!是一堆逻辑(运算)和一堆数据组合的数学模型!
函数的参数传递
在很久之前学习c++时,最高不明白的就是这个函数里的参数,虽然学过数学,知道参数在数学逻辑算式的作用是什么,也知道编程中的参数其实类似于数学逻辑算式中的参数作用。但不理解的是参数的传递规则和作用域。
而现在,用文件夹的视角,让我很容易理解参数的价值左右和相应的作用域为什么这么设计了。
(1)先展示一下参数的传递正常机制情况
i=3
j=4
def gougu(a,b):
e = a2+b3
return e
print(gougu(i,j))
上述代码中,1、2两行的参数首先传递给了print(gougu(i,j))中的i和j,由于1、2和7行属于函数gougu外部的变量,两者传递需要同名,否则识别不到!
c=3
d=4
def gougu(c,d):
c = c2+d2
a = c/2
return c
print(gougu(a,b))#将c、d改成a、b后会报找不到变量的错误
Traceback (most recent call last):
File “C:/Users/think/Desktop/2.py”, line 7, in
print(gougu(a,b))
NameError: name ‘a’ is not defined
但我们却可以让print(gougu(i,j))和def gougu(c,d)两个gougu里面的参数名称不同。因为一个是函数的定义,而一个是函数的引用。等于我们用print(gougu(i,j))中的i和j与def gougu(c,d)中的c和d的位置地址对应,将i和j获取到的值或者地址赋给def gougu(c,d)中的c和d,进行“通电”,进而启动函数。
正常的机制说完了,为了看清楚传递机制的内涵原理,我们进行下面的变化启发
(2)函数可以不带参数,直接引用外面的数据,但函数内却无法改动外部不可变数据类型(整数、字符串,因为是相对地址传递——也称为值传递)的数据,不过可以改变外部可变类型的数据(因为是绝对地址传递——又称为地址传递)。为什么这样传递?只能“怪罪”于Python的创造人了!
c=3
d=4
def gougu(c,d):
c = c2+d2
a = c/2
return c
print(gougu(c,d))
先解释一下上面的这段程序。首先,我们看到的print(gougu(c,d))中的c和d,与def gougu(c,d)中的c和d全然不同,现在第7行的这个print()从缩进层级就能看出来,属于函数def的外部,那print(gougu(c,d))中的c和d指的是去引用外部这个模块中的参数——即第1行和第2行的两个c=3,d=4的数值。
而def gougu(c,d)中的c和d仅仅是个内存空间,而c和d是这个空间的标识符。或者说这个空间属于def定义后的gougu地址下的内存,与外部是隔了一个gougu所代表的地址,外界是无法直接访问到的。而且这种无法访问,还不像class类那样,可以通过成员寻址运算符“.”点号来访问。
i=3
j=4
def gougu(a,b):
e = a2+b3
d=5
return e
print(gougu(i,j))
print(gougu.d)
Traceback (most recent call last):
File “C:/Users/think/Desktop/2.py”, line 8, in
print(gougu.d)
AttributeError: ‘function’ object has no attribute ‘d’
前面也说过这种传递机制了,这里只是在啰嗦一下,但其实我们可以让传递失效,让函数直接从外部去拿取参数。
i=3
j=4
def gougu(a=0,b=0):#当a=0,b=0 ,也不会影响e的计算结果还是73
e = i2+j3
return e
print(gougu(i,j))
从上面就能看出,gougu在def的时候,e = i2+j3中的i和j直接是从外部拿取的,即使print(gougu(i,j))中的i和j做了将自己传递给def gougu(a=0,b=0)的动作,但def gougu(a=0,b=0)并没有“领情”。因为,在整个功能主体代码块中,a和b这两个参数都没有得到利用,仅仅作为gougu这个函数的某两个参数放在那里了而已。
其次,我想说的是,函数的参数放在括号()里面和函数主体中写的变量,没有什么区别,都是被函数当做自己地址下面的变量了而已。
i=3
j=4
def gougu(a,b):
e = a2+b3
return e
print(gougu(i,j))
上面的代码和下面的得到的结果相同
i=3
j=4
def gougu():#没有参数
e = i2+j3 #直接从外面引用
return e
print(gougu())
结果还是73
同样,我也可以把原来在def gougu(a,b)中的a和b放入函数的主体里面,同样也能传递过去!
i=3
j=4
def gougu():
a=i #道理很简单,既然前面都已经说了,函数内部的变量可以直接去外部引用
b=j #那函数的内部的局部变量当然也可以引用外部的变量值
e = a2+b3
return e
print(gougu())
而下面这段代码向我们展示了参数的传递机制
i=3
j=4
def gougu(a,b):#发现a,b的两个参数根本没有被用过
e = i2+j3 #直接从外部调用i和j
return e
print(gougu(i,j))
既然写在括号里面的参数和放在函数内部的变量没什么两样,都是作为函数内部的变量而已,只不过写在()内部的参数位置,可以有效对应,不会乱掉,而如果你在函数的主体功能区去写传递性,虽然函数具有从外部引用的特征,但这样会大大降低灵活性。比如看下面的代码:
c=3 #把i变成了c
d=4 #把j变成了d
def gougu():
a =i#这个地方也必须同时改动,因为函数直接从外部引用了,要改为a=c
b =j
e = a2+b3
return e
print(gougu())
你会发现,必须要改动def gougu中的e = i2+j3的i和j也要对应修改,因为引用太过于直接了
i=3
j=4
def gougu(a,b):
e = a2+b3
return e
print(gougu(i,j))#通过参数来传递,def gougu(a,b)就不用再改动
即使遇到下面的情况体会会更深
i=3
j=4
def gougu(a,b):
e = a2+b3
return e
print(gougu(i,j))
当另一个人也编写了一个调用def gougu(a,b):有参数形式的传递,
即使有一万个人需要调用def gougu(a,b),也不用像前面那样,因为把引用写在了
函数功能主体直接引用了,导致每次调用都要修改函数的定义,那样就失去了函数的
重复调用的价值了!!!
m=6
n=8
print(gougu(m,n))
参数的可变性或影响性说明
按照很多资料的说明,函数的参数传递,分为值传递和址传递两种,也有说法是不可变类型数据的传递(整数型、字符串型、元组型)和可变变量的传递(list、tuple、dictionary)。对应的,不可变类型数据其实就是值传递,而可变类型数据传递就是址传递。
其实传递的都是地址,但我认为(不是正确的,只是帮助我自己理解)不可变类型数据传递的是相对地址,而可变类型的数据传递的是这些数据结构的绝对地址。
从前面数据类型的说明来看,int、string、tuple在Python中是创建了就不再变化地址了,比如i=2,改成i=3,不是将i赋值为3,而是在类型池中创建一个地址来放3这个值,再把这个地址传递给i这个变量。
这也就是我们说的,变量没有类型,数据才有类型!!!
再回来看待很多资料里面说明的函数参数传递,其实就是想强调当函数发生从外部引用数据后,对从外部引用的数据会有什么影响的问题。
看下面的代码
i=3
j=4
def gougu(a,b):
e = a2+b2
i = 5
print(i)
return e
print(gougu(i,j))
print(i)
结果:
5 #函数内
25
3 #函数外的i变量依然没有什么影响
对比list这些可变影响——就是想警告我们,一定要注意,函数处理后,对函数会对从外界引用的这些类型的数据有影响。
mylist=[1,2]
def yingxiang(mylist):
mylist.append([3,4])
print(“函数内部:”,mylist)
return
yingxiang(mylist)
print(mylist)
结果
函数内部: [1, 2, [3, 4]]
[1, 2, [3, 4]]
在对比一下:
mylist=[1,2]
def yingxiang(mylist):
mylist=[3,4]
print(“函数内部:”,mylist)
return
yingxiang(mylist)
print(“函数外部:”,mylist)
结果:
函数内部: [3, 4]
函数外部: [1, 2]
想一想为什么?因为我们在函数内部用了赋值的运算“=”,这样就会造成看似相同的mylist,但通过赋值运算,函数内部的那个mylist已经不再是外部的那个全局变量了。
对比一下下面的程序
mylist=[1,2]
def yingxiang(mylist):
mylist.append([3,4]) #没有了赋值运算,不会产生新的局部变量
print(“函数内部:”,mylist)
return
yingxiang(mylist)
print(“函数外部:”,mylist)
结果:
函数内部: [1, 2, [3, 4]]
函数外部: [1, 2, [3, 4]]
mylist=[1,2]
def yingxiang(a):#把参数中的mylist换成a,结果不受影响
a.append([3,4])#只要不在功能主体中赋值,增加了新的局部变量
print(“函数内部:”,a)
return
yingxiang(mylist)
print(“函数外部:”,mylist)
函数内部: [1, 2, [3, 4]]
函数外部: [1, 2, [3, 4]]
最后验证一下:
mylist=[1,2]
def yingxiang(a):
a=mylist.append([3,4])#赋值运算后,产生了一个局部变量a
print(“函数内部:”,a)
return
yingxiang(mylist)
print(“函数外部:”,mylist)
结果为:
函数内部: None
函数外部: [1, 2, [3, 4]] #你会发现影响了外部,但内部却是none
mylist=[1,2]
def yingxiang(a):
a=mylist.append([3,4])
print(id(a))
print(“函数内部:”,a)
return
yingxiang(mylist)
print(id(mylist))
print(“函数外部:”,mylist)
结果
140709513211104 #发现赋值运算产生的局部变量地址和mylist不同的
函数内部: None
1414285118344
函数外部: [1, 2, [3, 4]]

Python的函数理解外传相关推荐

  1. python参数传递方法_深入理解python中函数传递参数是值传递还是引用传递

    python 的 深入理解python中函数传递参数是值传递还是引用传递 目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是&q ...

  2. 【Python】深入理解Python函数的9个黄金法则

    编程离不开函数.Python的函数除了具备传统意义上的函数特征外,又被赋予了其他一些特性,让它更灵活.更强大.这篇文章结合之前我推荐的一本Python宝书,又添加一些我的实践和理解,总结了深入理解Py ...

  3. python函数参数传递机制_Python 学习笔记(一) 理解Python的函数传参机制

    对于刚接触Python不久的新手,Python的函数传参机制往往会让人迷惑.学过C的同学都知道函数参数可以传值或者传地址.比如下面这段代码 点击(此处)折叠或打开 void func(int inpu ...

  4. 如何理解python中的函数_如何理解“python中函数是一等公民”?

    python.js.scala等支持函数式编程的语言中,是如何体现"函数是一等公民(first class)"的?而在c/c++.java等静态语言中的一等公民又是什么?如何体现的 ...

  5. [1-1 main ]Python主函数及其示例:理解__main_

    Python主函数及其示例:理解__main_ 在深入研究Python编码之前,我们熟悉了Python的主要功能及其重要性. 考虑以下代码 def main():print "hello w ...

  6. python怎么理解函数的参数_理解Python中函数的参数

    定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了.对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调用者无需了解 ...

  7. python的translate()函数理解

    python 3 函数名:translate() 功能:对字符进行交换或过滤 语法:translate(table, /) 使用例子: import string # 引用 maketrans 函数. ...

  8. python第三方库中函数调用_Python学习笔记(2)——Python的函数、模块、包和库...

    初识Python,对于没有接触过编程的我,恐怕只能听懂什么是函数,这里介绍一下几个概念,并给出Python在调用方面的独特之处. 函数 理解为数学上的函数就可以了.下载安装完python后,并不是所有 ...

  9. python not函数_python 函数

    1 为什么使用函数 在没有接触函数时,有时候需要将一个功能多次写,如果需要修改其中一个变量,则需要把所有实现该功能的代码一处一处改.不利于代码维护,代码量大了,组织结构也会很不清晰. 所以总结不使用函 ...

  10. exit函数_全面深入了解 Python 魔法函数

    (点击上方公众号,可快速关注一起学Python) 作者:浪子燕青       链接: http://www.langzi.fun/Python魔法函数.html 魔法函数概念 魔法函数是以双下划线开头 ...

最新文章

  1. Python urllib和urllib2模块学习(一)
  2. 关于网站URL转码的问题
  3. python grpc 并发_用Python进行gRPC接口测试(二)
  4. 小科知道20211202
  5. java视频流传输_目前在Web浏览器中流式传输实时视频的最佳做法?
  6. SAP SuccessFactor学习中心的通知机制
  7. 数模国赛要点与注意事项全分享!
  8. 【微信小程序】java最简单观察者模式
  9. nodejs图片读取
  10. jq判断是否为整数_jquery怎么判断是否是数字?
  11. 原型模式(Prototype )
  12. 多伦多大学计算机专音乐专业,多伦多大学音乐专业有哪些申请要求?
  13. 一个典型的高精度室内UWB定位系统是怎么炼成的?
  14. 将本珊计算机组成原理,本珊
  15. armbian ubuntu 桌面_armbian安装lxde桌面
  16. 闪购网站Gilt从Rails迁移到Scala
  17. 提问:微信网页授权到第三方调用错误、调用微信公众号扫码登陆错误、微信SCOP权限错误或没有权限
  18. Ribbon负载均衡及Feign消费者调用服务
  19. linux下构建Smokeping网络监控平台
  20. 生成百度网盘文件目录_艾孜尔江撰稿

热门文章

  1. lecture9-提高模型泛化能力的方法
  2. 启发式算法 Heuristic
  3. Google kickstart 2013 Practice Round Captain Hammer 题解
  4. 加州大学戴维斯计算机博士生,2020年加州大学戴维斯分校博士读几年
  5. 信息流广告如何操作?一文搞懂!
  6. Linux 学习课堂笔记1
  7. RxView学习及实现按钮防抖功能
  8. 完美卸载office
  9. 【Android】Android 封装 Http 请求工具
  10. 网站搭建:从零搭建个人网站教程(1)