Python学习笔记之函数
这篇文章介绍有关 Python 函数中一些常被大家忽略的知识点,帮助大家更全面的掌握 Python 中函数的使用技巧
1、函数文档
给函数添加注释,可以在 def 语句后面添加字符串,这样的注释被称为 文档字符串,它将作为函数的一部分储存起来
>>> def square(x):
'Calculates the square of the number x.'
return x*x
可以通过内置属性 __doc__ 访问文档字符串
>>> square.__doc__
# 'Calculates the square of the number x.'
也可以通过内置方法 help() 访问文档字符串
>>> help(square)
# Help on function square in module __main__:
# square(x)
# Calculates the square of the number x.
2、参数魔法
在 C++ 中,函数参数的传递方式有两种,一是按值传递,二是按引用传递,那么在 Python 中参数传递方式是什么呢?
我们先来看一个例子
>>> name = 'Andy'
>>> def change(string):
string = 'Function'
>>> change(name)
>>> name
# 'Andy'
函数形参变量的修改并不能影响实参变量的取值,这有点像按值传递,所以 Python 中参数的传递方式是按值传递吗?
别急,我们再来看另一个例子
>>> names = ['Andy']
>>> def change(strings):
strings[0] = 'Function'
>>> change(names)
>>> names
# ['Function']
在这个例子中,函数形参变量的修改改变了实参变量的取值,这又有点像按引用传递,为什么会这样呢?
为了理解清楚这里面的关系,我们需要深入了解其内在的原理
首先,我们需要知道,在 Python 中变量赋值实际上并不是将值储存在变量中
反倒有点像将变量名贴在值上,以下图片展示了调用语句 x = 'Hello' 的一种直观理解

该过程在内存中的理论模型如下(变量可以视为指向值的名称):

变量可以分为可变类型和不可变类型,当修改可变对象时,将直接修改物体内的值
但是在“修改”不可变对象时,由于物体内的值不可改变,所以 Python 采取了一种特殊的方法处理这种情况
即将标签贴在另一个储存了新内容的物体上,储存了旧内容的物体在没有标签指向时被系统自动回收
以下图片展示了这一过程的直观理解

该过程在内存中的理论模型如下:

好,下面让回到最初的问题:为什么将字符串传入函数之后不会改变,而将列表传入函数之后会改变呢?

现在我们总算明白了:
当传入可变对象作为函数参数时,函数内的修改会改变原来的值
当传入不可变对象作为函数参数时,函数内的修改不会改变原来的值
假如我们想传入可变对象(例如列表)作为函数参数同时又不想修改原列表的值,该怎么办呢?
这时我们可以传入列表的副本即可,例如 change(names[:])
又假如我们想传入不可变对象(例如字符串)作为函数参数同时又想修改原字符串的值,该怎么办呢?
不好意思,没有办法!这时我们只能从函数中返回所需要的值,并赋值给原变量,例如 name = change(name)
3、关键字参数
我们一般使用的参数称为 位置参数,因为它们的位置至关重要,在调用函数时我们甚至可以忽略它们的名称
>>> def test(greeting,name):
print(greeting,name)
>>> test('Hello','World') # 参数名称无关重要,只需要关注它们的位置即可
# Hello World
但是,一旦参数很多,难以记住每一个参数的位置时,可以在调用函数的时候指定参数的名称,这称为 关键字参数
>>> def test(greeting,name):
print(greeting,name)
>>> test(name='World',greeting='Hello')
# Hello World
关键字参数更重要的作用是给参数 指定默认值
>>> def test(greeting='Hello',name='World'):
print(greeting,name)
>>> test()
# Hello World
>>> test(name='Helen')
# Hello Helen
注意:指定默认参数时,一定要从后面开始指定,像 def test(greeting='Hello',name) 这样的语法是错误的
4、收集参数
设想我们遇到这样一种情况,当函数参数的数量不确定时,我们应该怎么处理呢?
这时,我们可以使用 收集参数,收集参数在 定义函数 时使用星号 * 实现
在 调用函数 时,将输入的参数作为一个元组储存起来
>>> def test(a,b,*c):
print(a,b,c)
>>> test(1,2,3,4,5,6)
# 1 2 (3, 4, 5, 6)
假如我们把收集参数放在前面会发生什么呢?比如说这样
>>> def test(a,*b,c):
print(a,b,c)
>>> test(1,2,3,4,5,6) # TypeError: test() missing 1 required keyword-only argument: 'c'
这时会产生一个语法错误,因为星号意味着会收集余下的所有参数,导致形参 c 无法接收实参而产生错误
我们可以使用关键字参数解决这个问题
>>> def test(a,*b,c):
print(a,b,c)
>>> test(1,2,3,4,5,c=6)
1 (2, 3, 4, 5) 6
使用星号还存在一个问题,即它无法收集关键字参数
>>> def test(*paras):
print(paras)
>>> test(1,2,3) # 收集位置参数,正常
# (1, 2, 3)
>>> test(x=1,y=2,z=3) # 收集关键字参数,错误
# TypeError: test() got an unexpected keyword argument 'x'
这时我们可以使用双星号 ** 解决这个问题,此时得到的将会是一个字典,而非元组
另外要注意双星号不能收集位置参数
>>> def test(**paras):
print(paras)
>>> test(x=1,y=2,z=3) # 收集关键字参数,正常
# {'x': 1, 'y': 2, 'z': 3}
>>> test(1,2,3) # 收集位置参数,错误
# TypeError: test() takes 0 positional arguments but 3 were given
所以,我们一般可以使用以下格式同时收集位置参数和关键字参数:function(*args, **kwds)
5、分配参数
分配参数 与收集参数执行相反的操作,在 调用函数 时使用星号 * 或者双星号 ** 实现
>>> def test(x,y):
print(x,y)
>>> paras1 = (1,2)
>>> test(*paras1) # 将元组变成独立的位置参数
# 1 2
>>> paras2 = {'x':1,'y':2}
>>> test(**paras2) # 将字典变成独立的关键字参数
# 1 2
5、作用域
变量究竟是什么呢?其实可以将变量视为指向值的名称,这或许有点类似于字典(在字典中键指向值)
实际上我们的确是在使用一种看不见的字典,一个名为 vars() 的内置函数可以返回这个看不见的字典
我们称这个看不见的字典为 作用域
>>> x = 1
>>> vars()['x']
# 1
一般而言,不应该修改 vars 返回的字典,因为这会产生意想不到的后果
下面考虑这样一个问题:为什么函数内局部变量的修改不会影响函数外同名的全局变量呢?
>>> x = 1
>>> def change():
x = 10
>>> change()
>>> x
# 1
这是因为在调用函数时,Python 会创建一个新的作用域,赋值语句在这个局部作用域中执行,而不影响全局作用域中的变量
那么,现在假如我们想在函数中访问全局变应该怎么办呢?其实,这通常不会有任何问题
>>> x = 1
>>> def add(y):
print(x + y)
>>> add(2)
# 3
但是,当全局变量和局部变量同名呢?
>>> x = 1
>>> def add(x):
print(x + x)
>>> add(2)
# 4
此时,局部变量会覆盖全局变量
我们可以使用 globals() 函数解决这个问题,globals() 函数类似于 vars() 函数,返回一个包含全局变量的字典
>>> x = 1
>>> def add(x):
print(x + globals()['x'])
>>> add(2)
# 3
最后,假如我们想在函数中需改全局变量应该怎么办呢?
我们应该使用关键字 global 明确告诉 Python,该变量就是全局变量
>>> x = 1
>>> def change():
global x
x = 10
>>> change()
>>> x
# 10
6、lambda 函数
最后一个要介绍的知识点就是 lambda 函数
lambda 函数即匿名函数,省去了函数命名的烦恼,对于一些功能简单的函数尤为合适
其基本语法如下:lambda parameters : expression
parameters:用逗号分隔的变量列表,可选,代表传入函数的参数expression:简单语句,不能包含 return,代表函数的输出结果
示例 1:实现简单的加法
>>> # 例如下面的语句表示:输入x、y,输出 x + y
>>> add = lambda x,y: x+y
>>> # 我们可以像使用正常函数一样使用 lambda 函数
>>> add(1,2)
# 3
>>> # 但是,上面的用法并不是 lambda 函数最常用的用法,因为 lambda 函数的出现是为了创建匿名函数
示例 2:使用在 sorted 函数中,指定排序规则
>>> # 按绝对值排序
>>> li = [3,-2,4,-1,5]
>>> sorted(li, key = lambda x: abs(x))
# [-1, -2, 3, 4, 5]
示例 3:使用在 filter 函数中,指定过滤规则
filter 函数的使用格式如下:
filter(function,sequence)filter 将 function 作用于 sequence 中的每一个元素,并返回作用后结果为 true 的元素
>>> # 过滤奇数
>>> list(filter(lambda x: x % 2 == 0, range(10)))
# [0, 2, 4, 6, 8]
示例 4:使用在 map 函数中,指定处理规则
map 函数的使用格式如下:
map(function,sequence)map 将 function 作用于 sequence 中的每一个元素,并返回作用后的元素
>>> # 求平方
>>> list(map(lambda x: x**2, range(10)))
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
示例 5:使用在 reduce 函数中,指定处理规则
reduce 函数的使用格式如下:
reduce(function,sequence)reduce 将 function 迭代作用于 sequence 中的元素
例如:reduce(function, [x1 , x2 , x3]) = function(function(x1 , x2) , x3) )
>>> # 求累加和
>>> from functools import reduce
>>> reduce(lambda x,y: x + y, range(10))
# 45
【 阅读更多 Python 系列文章,请看 Python学习笔记 】
Python学习笔记之函数的更多相关文章
- 小甲鱼:Python学习笔记003_函数
>>> # 函数>>> def myFirstFunction(params1,params2...): print("这是我的第一个函数!") ...
- Python学习笔记 - day6 - 函数
函数 函数在编程语言中就是完成特定功能的一个词句组(代码块),这组语句可以作为一个单位使用,并且给它取一个名字.可以通过函数名在程序的不同地方多次执行(这叫函数的调用).函数在编程语言中有基本分为:预 ...
- Python学习笔记系列——函数
今年下半年的计划主要是Python和Mysql了,公司不方便看书和视频,就照着廖雪峰的Python网站开始看了.以下纯为个人笔记记录,若是想系统学习的小伙伴还是看这里的好一些,毕竟系统.https:/ ...
- Python学习笔记(五)函数和代码复用
函数能提高应用的模块性,和代码的重复利用率.在很多高级语言中,都可以使用函数实现多种功能.在之前的学习中,相信你已经知道Python提供了许多内建函数,比如print().同样,你也可以自己创建函数, ...
- python学习笔记(4)--函数
1.函数 函数是指将一组语句的集合通过一个名字封装起来.要想执行这个函数,只需调用其函数名即可. 函数的特性: 1.减少重复代码 2.使程序变的课扩展 3.使程序变得易维护 语法定义: def pri ...
- Python学习笔记-Day3-python函数
1.为什么要用函数? 提高代码重复利用率,减少代码冗余.封装模块化代码,便于调用 2.函数声明定义(注意:函数先声明后调用) 注意:函数的reture循环中的exit功能一样(函数不执行,终止) 函数 ...
- Python学习笔记11—函数
建立第一个函数 /usr/bin/env Python #coding:utf-8 def add_function(a,b): c = a+b print c if __name__==" ...
- Python学习笔记7-把函数当参数传递、指定可变参数
把函数当参数传递 # 函数参数传递 # 面向对象编程就是把对象传来传去 # 面向函数编程就是把函数传来传去 def mytest(num): return num * 2 # # 不光可以传递变量,还 ...
- Python学习笔记_week3_函数
一.介绍 1.面向对象(华山派)--->类(独门秘籍)--->class(定义的关键字) 2.面向过程(少林派)--->过程--->def 3.函数式编程(逍遥派)---> ...
随机推荐
- MongoDB改动、删除文档的域属性实例
MongoDB改动.删除文档的域属性实例 在站点的开发中,可能最初的设计不合理.或者后期业务的变更,会造成文档结构会有些无用的属性.须要去删除或改动.因为MongoDB 是无 Schema 的,不像关 ...
- 学界| UC Berkeley提出新型分布式框架Ray:实时动态学习的开端—— AI 应用的系统需求:支持(a)异质、并行计算,(b)动态任务图,(c)高吞吐量和低延迟的调度,以及(d)透明的容错性。
学界| UC Berkeley提出新型分布式框架Ray:实时动态学习的开端 from:https://baijia.baidu.com/s?id=1587367874517247282&wfr ...
- Elias-Fano编码算法——倒排索引压缩用,本质上就是桶排序数据结构思路
Elias-Fano编码过程如下:把一组整数的最低l位连接在一起,同时把高位以严格单调增的排序划分为桶. Example: 2, 3, 5, 7, 11, 13, 24 Count in unary ...
- heap堆&&priority_queue优先队列
堆(heap)不是stl中的东西...它分为 max heap 和min heap. 但我不想用这些,而是采用了priority_queue,优先队列,定义在queue中.顾名思义,它的作用就是无论怎 ...
- LA3276
费用流 这种棋盘模型大概都是网络流吧 首先我们知道棋子之间不会影响到达目标的步数,那么就好做了,枚举终点,然后就是最小权匹配了,因为就是寻找总和最小,然后费用流就行了. #include<bit ...
- Reactive Native开发环境搭建
root@zhongzhenhua-virtual-machine:~/AndroidCode# repo init -u https://android.googlesource.com/platf ...
- css 浮动问题详解
浮动(float),一个我们即爱又恨的属性.爱,因为通过浮动,我们能很方便地布局: 恨,浮动之后遗留下来太多的问题需要解决,特别是IE6-7(以下无特殊说明均指 windows 平台的 IE浏览器). ...
- poj2975 Nim(经典博弈)
Nim Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 5866 Accepted: 2777 Description N ...
- Django day14(一) cookie
一: Cookie 1. Cookie是什么?存储在客户端浏览器上的键值对 2. 原理: 是服务器产生,发给客户端浏览器,浏览器保存起来,下次发请求,会携带这个键值对到服务器 4. Cookie的覆 ...
- Could not create the view: An unexpected exception was thrown. Myeclipse空间报错
我的路径D:\MyEclipse 10\.metadata\.plugins\org.eclipse.core.runtime\.settings 我也遇到过这个问题,就是工作空间的问题好像是删除你工 ...