Python学习笔记009—函数
1. 空函数
如果想定义一个什么事也不做的空函数,可以用pass语句:
def nop():
pass
pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。
2. 容易混肴的函数使用方式
函数的赋值其实就是将函数名指向函数体。
2.1 函数名其实也是一个变量
例如,
def func():
return "Python"
print (func())
print (func)
func = 100
print (func)
print (func())
输出结果
Python
<function func at 0x7f4aa8a66f28>
100
Traceback (most recent call last):
File "test.py", line 27, in <module>
print (func())
TypeError: 'int' object is not callable
第一次输出是调用函数的输出结果
第二次输出是函数所在的物理存储位置
第三次输出是将函数名(变量)重新绑定一个值后的输出结果
第四次输出是因为“整型不能函数调用”,因为将func绑定100后,func已经成为整型变量,func()是进行的函数调用,所以报错!
2.2 函数的绑定规则
情形1
def func(a):
return a
b = func(6)
print(b)
输出结果
6
情形2
def func(a):
return a
b = func
print(b(6))
输出结果
6
情形3(该情况类似情形1)
def func(a=[100,200]):
return a
x = func()
x.append(1)
print("x:", x)
输出结果
X: [100, 200, 1]
情形4(该情况类似情形2)
def func(a=[100,200]):
return a
x = func
x().append(1)
print("x:", x())
输出结果
x: [100, 200, 1]
情形5
def func(a=[100,200]):
return a
x = func
x().append(1)
print("x:", x)
输出结果
x: <function func at 0x7f818e8d5f28>
该输出结果为函数所在的位置
情形6
def func(a=[100,200]):
return a
x = func
x.append(1)
print("x:", x)
输出结果
Traceback (most recent call last):
File "test.py", line 24, in <module>
x.append(1)
AttributeError: 'function' object has no attribute 'append'
错误的原因是:函数“function”对象没有“append”属性
2.3 函数的绑定方式
def func(a=[100,200]):
return a
x = func()
y = func()
print(func)
print(id(x))
print(id(y))
x.append(1)
print("y:", y)
y.append(2)
print("x:", x)
x.append(3)
print("x:", x)
print("y:", y)
输出结果
<function func at 0x7feed4d4ef28> 140663724970760 140663724970760 y: [100, 200, 1] x: [100, 200, 1, 2] x: [100, 200, 1, 2, 3] y: [100, 200, 1, 2, 3]
我们发现,x和y绑定的函数为一个地址,也即当x绑定值改变时,y值也随之也改变。
但是函数 func 与函数 x 、 y 的地址是不一样的;将140663724970760转成16进制时,得到
>>> hex(140098127414024) '0x7f6b231e4308'
所以地址是有区别的!
2.4 序列传参(元组传参)
代码片段1
def func(a,b):
print(a+b)
func(1,2)
func(*(1,2))
输出结果
3 3
当形参是与实参不一致时
def func(a,b):
print(a+b)
func(*(1))
运行结果
Traceback (most recent call last):
File "test01.py", line 4, in <module>
func(*(1))
TypeError: func() argument after * must be an iterable, not int
本段代码产生错误的原因是元组形式错误导致的。在*后面必须是可迭代的,而不是整数
执行错误后,没有向下执行。
代码片段2
def func(a,b):
print(a+b)
func(*(1,))
运行结果
Traceback (most recent call last):
File "test01.py", line 4, in <module>
func(*(1,))
TypeError: func() missing 1 required positional argument: 'b'
该段代码运行错误是因为实参少于形参个数
代码片段3
def func(a,b):
print(a+b)
func(*(1,2,3))
运算结果
Traceback (most recent call last):
File "test01.py", line 4, in <module>
func(*(1,2,3))
TypeError: func() takes 2 positional arguments but 3 were given
该段代码运行错误的原因是因为实参多于形参个数
总结:当仅有元组传参时,实参个数必须与实参个数一致
代码片段4
def info(*var):
print(var)
for a in var:
print(a)
info(*(1,2,3))
print("------------")
info(1,2,3)
输出结果
(1, 2, 3) 1 2 3 ------------ (1, 2, 3) 1 2 3
2.4 序列传参(列表传参)
def func(a,b):
print(a+b)
func(*[1,2])
输出结果
3
其实列表传参与元组传参在功能上没有明显区别
2.5 关键字传参
关键字传参只要关键字匹配就可以,顺序可以改变。
def func(a,b):
print(a+b)
func(b=1,a=2)
func(a=1,b=2)
输出结果
33
当改变一下
def func(a,b):
print(a+b)
func(a=1,2)
输出结果
File "test01.py", line 4
func(a=1,2)
^
SyntaxError: positional argument follows keyword argument
语法错误:位置参数在关键字参数后
有位置参数的,位置参数必须写在关键参数前面;换句话说,一旦出现关键字参数,其后不能出现位置参数
def func(a,b):
print(a+b)
func(1,a=2)
输出结果
Traceback (most recent call last):
File "test01.py", line 4, in <module>
func(1,a=2)
TypeError: func() got multiple values for argument 'a'
错误类型:函数的参数a得到了多个值。
很明显,当形参和实参位置赋值完毕后,再按照关键字参数再赋值,最后发现形参a有多个值,而没有报形参b值缺少。可以说明实参向形参传值时不存在形同形参覆盖问题。
2.6 字典传参
代码片段1
def print_str(a, b):
print(b)
print(a)
d = {"b":2,"a":1}
print_str(**d)
输出结果
2 1
代码片段2
def print_str(a, b):
print(b)
print(a)
print_str("b":1,"a":2)
输出结果
File "test01.py", line 5
print_str("b":1,"a":2)
^
SyntaxError: invalid syntax
语法错误,这样写不是字典所要求的输入形式
代码片段3
def print_str(a, b):
print(b)
print(a)
print_str({"b":1,"a":2})
输出结果
Traceback (most recent call last):
File "test01.py", line 5, in <module>
print_str({"b":1,"a":2})
TypeError: print_str() missing 1 required positional argument: 'b'
因为缺少参数 b 而报错,该段代码中将字典 {"b":1,"a":2} 作为一个参数传给了 a ;将其进行修改
代码片段4
def print_str(a, b):
print(a)
print(b)
print_str({"b":1,"a":2},1)
输出结果
{'b': 1, 'a': 2}
1
不难看出,该段代码中将字典当作一个参数传给形参 a ,将实参 1 传给形参 b ,其实,这就是位置传参
其实字典传参的输入形式如代码5所示
代码片段5
def print_str(a, b):
print(a)
print(b)
print_str(**{"b":1,"a":2})
输出结果
2 1
代码片段6
def print_str(**dict):
print(dict)
print_str(**{"b":1,"a":2})
输出结果
{'a': 2, 'b': 1}
代码片段7
def print_str(**dict):
print(dict)
print_str({"b":1,"a":2})
输出结果
Traceback (most recent call last):
File "test01.py", line 4, in <module>
print_str({"b":1,"a":2})
TypeError: print_str() takes 0 positional arguments but 1 was given
函数有0个位置参数,但是实参却有一个别给定
如果按照这个错误提示,当没有任何实参时,应该也不会报错
代码片段8
def print_str(**dict):
print(dict)
")
print_str( )
输出结果
{}
123
代码片段9
def print_str(**dict):
print(dict)
")
print_str("b":1,"a":2)
输出结果
File "test01.py", line 5
print_str("b":1,"a":2)
^
SyntaxError: invalid syntax
说明代码述写的时候已经出错
代码片段10
def print_str(**dict):
print(dict)
print_str(b=1,a=2)
输出结果
{'a': 2, 'b': 1}
代码片段11
def func(**kwargs):
print(kwargs)
print("参数个数:", len(kwargs))
for k,v in kwargs.items():
print(k, "->", v)
func(x = 10, y = 20, z = 30)
d = {"x":10, "y":20, "z":30}
func(**d)
func(**{"a":30, "b":40, "c":50, "d":60})
func(**{"a":"你好", "b":40, "c":50, "d":60})
输出结果
{'y': 20, 'z': 30, 'x': 10}
参数个数: 3
y -> 20
z -> 30
x -> 10
{'y': 20, 'z': 30, 'x': 10}
参数个数: 3
y -> 20
z -> 30
x -> 10
{'a': 30, 'c': 50, 'b': 40, 'd': 60}
参数个数: 4
a -> 30
c -> 50
b -> 40
d -> 60
{'a': '你好', 'c': 50, 'b': 40, 'd': 60}
参数个数: 4
a -> 你好
c -> 50
b -> 40
d -> 60
3 混合传参
混合传参形式是将位置传参、关键字传参、序列传参(元组传参、列表传参)、字典传参结合使用。
3.1 位置传参+序列传参
序列传参中的元组传参与列表传参没明显区别,本处仅以元组传参为例。
代码片段1
def print_info(arg1, *var):
print(" 参数1:", arg1)
print(" 其他参数:")
print(var)
for a in var:
print(a)
print_info(100,)
print("------------")
print_info(100)
print("------------")
输出结果
参数1: 100 其他参数: () ------------ 参数1: 100 其他参数: () ------------
当实参满足第一个位置形参后,即使后面的元组参数是空也不报错
代码片段2
def print_info(arg1, *var):
print(" 参数1:", arg1)
print(" 其他参数:")
print(var)
for a in var:
print(a)
print_info(100, 1, 3)
print("------------")
print_info(100, *(1, 3))
print("------------")
输出结果
参数1: 100 其他参数: (1, 3) 1 3 ------------ 参数1: 100 其他参数: (1, 3) 1 3 ------------
当前面的实参个数满足位置参数个数后,后面的实参均默认为元组形参中的数值。
注意:以本代码为例,第一个位置参数不限于数字、字符串,也可以是元组或字典,为了更清楚地表达,见代码片段3
代码片段3
def print_info(arg1,arg2,arg3, *var):
print(" 参数1:", arg1)
print(" 参数1:", arg2)
print(" 参数1:", arg3)
print(" 其他参数:")
print(var)
for a in var:
print(a)
print_info((100,200),300,{"a":400,"b":500},600,700,800,900)
输出结果
参数1: (100, 200)
参数1: 300
参数1: {'b': 500, 'a': 400}
其他参数:
(600, 700, 800, 900)
600
700
800
900
代码片段4
def print_info(arg1, *var):
print(" 参数1:", arg1)
print(" 其他参数:")
print(var)
for a in var:
print(a)
a = (1,2)
b = [1,2]
print_info(100,a,200,300,b)
print("---------------------")
print_info(100,*a,200,300,*b)
输出结果
参数1: 100 其他参数: ((1, 2), 200, 300, [1, 2]) (1, 2) 200 300 [1, 2] --------------------- 参数1: 100 其他参数: (1, 2, 200, 300, 1, 2) 1 2 200 300 1 2
注意述写时候的细节
3.2 位置传参+字典传参
def func(a, **kwargs):
print (" 参数 a 是", a)
print(kwargs)
for key in kwargs:
print(key, kwargs[key])
func(10, y = 100, x = 200, z = 1000)
输出结果
参数 a 是 10
{'x': 200, 'z': 1000, 'y': 100}
x 200
z 1000
y 100
3.3 位置参数+序列参数+字典参数
函数代码均一样,如下段代码所示;该标题下的其他代码为函数调用代码,函数代码再调用代码中省略。
代码片段1
def print_args(arg1, *targs, **kwargs):
print(" arg1 是", arg1)
print(" targs:")
for t in targs:
print (t)
print(" kwargs:")
for key in kwargs:
print(key, kwargs[key])
代码片段2
print_args(1)
输出结果
arg1 是 1 targs: kwargs:
代码片段3
print_args(1, b=")
输出结果
arg1 是 1 targs: kwargs: c 3 b 2
代码片段4
print_args(1,2,3,4,b=")
输出结果
arg1 是 1 targs: 2 3 4 kwargs: b 2 c 3
代码片段5
a = 20
b = 30
t = (20, 100, 200)
print_args(10, b, *t, 4, b = 2, c = 3)
print("-------------------------")
print_args(10, b, *t, 4, **{"b":2, "c": 3})
输出结果
arg1 是 10 targs: 30 20 100 200 4 kwargs: b 2 c 3 ------------------------- arg1 是 10 targs: 30 20 100 200 4 kwargs: b 2 c 3
代码片段6
a = 20 b = 30 t = (20, 100, 200) print_args(10, b, b = 2, c = 3, *t, )
输出结果
arg1 是 10 targs: 30 20 100 200 kwargs: c 3 b 2
代码片段7
本段代码是将函数的形参顺序进行修改,修改后直接报错
File "test01.py", line 1
def print_args(arg1, **targs, *kwargs):
^
SyntaxError: invalid syntax
可以发现,形参的顺序是固定不变的。而实参的顺序是可以改变的。
4 特殊的规则
如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和job作为关键字参数。这种方式定义的函数如下:
def student(name, age, *, school, address):
print('name:', name, 'age:', age, 'school',
school, 'address', address)
student("zhang", 24, address = "北京海淀", school = "清华")
student("zhang", 24, **{"school": "清华", "address":"北京海淀"})
输出
name: zhang age: 24 school 清华 address 北京海淀name: zhang age: 24 school 清华 address 北京海淀
*后面的参数被视为命名关键字参数。
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:
def person(name, age, *args, city, job):
print(name, age, args, city, job)
命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错:
>>> person('Jack', 24, 'Beijing', 'Engineer')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: person() takes 2 positional arguments but 4 were given
以上仅是联系的一部分。
也可以参考廖雪峰的本章节博客https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431752945034eb82ac80a3e64b9bb4929b16eeed1eb9000
5 函数是否可执行属性
#函数名本质是变量 >>> callable(print) True >>> callable(print()) False >>> callable(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'a' is not defined >>> b = 1 >>> callable(b) False >>>
Python学习笔记009—函数的更多相关文章
- Python学习笔记之函数
这篇文章介绍有关 Python 函数中一些常被大家忽略的知识点,帮助大家更全面的掌握 Python 中函数的使用技巧 1.函数文档 给函数添加注释,可以在 def 语句后面添加独立字符串,这样的注释被 ...
- 小甲鱼: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 # # 不光可以传递变量,还 ...
随机推荐
- 具体解说Android的图片下载框架UniversialImageLoader之磁盘缓存(一)
沉浸在Android的开发世界中有一些年头的猴子们,预计都可以深深的体会到Android中的图片下载.展示.缓存一直是心中抹不去的痛.鄙人亦是如此.Ok,闲话不说.为了督促自己的学习.以下就逐一的挖掘 ...
- Android Studio 打包时 Signature Version 选择 V1 V2 说明
问题描述(v1和v2) Android 7.0中引入了APK Signature Scheme v2,v1是jar Signature来自JDKV1:应该是通过ZIP条目进行验证,这样APK 签署 ...
- 复习C语言:第一章
复习C语言中的5中基本类型,以及各个类型占用了多少个字节: #include <stdio.h> int main(void) { printf("int=%d\n", ...
- 【树莓派】树莓派与XBMC及Kodi、LibreELEC插件(二)
之前的相关文章参考: [树莓派]树莓派与XBMC及Kodi.LibreELEC插件(一) [树莓派]树莓派与XBMC及Kodi.LibreELEC插件(二) [树莓派]树莓派与XBMC及Kodi.Li ...
- mysql加减时间-函数-时间加减
select timediff('23:40:00', ' 18:30:00'); -- 两时间相减 SELECT substring( timediff(,) ----“:”相减返回小时:分钟 -- ...
- Android使用OKHttp库实现视频文件的上传到服务器
目录 1 服务器接口简介 2 Android端代码实现 2.1 xml布局文件 2.2 Activity类 2.3 Okhttp网络通信类 1 服务器接口简介 此处我使用的服务器接口是使用Flask编 ...
- Flash:利用Bitmapdata,ColorTransform,DrawPath,制造绚丽效果
JamesLi的文章:http://www.adobe.com/cn/devnet/actionscript/articles/silkflash-as.html 总结一下绚丽效果的核心: 1.利用一 ...
- countif
countif(range,criteria) range:表示要计算其中非空单元格数目的区域 criteria:表示统计条件 eg:求得分大于等于80分小于90分的学生数
- appium界面运行过程(结合日志截图分析)
appium界面运行过程: 1.启动一个http服务器:127.0.0.1:47232.根据测试代码setUp()进行初始化,在http服务器上建立一个session对象3.开始调用adb,找到连接上 ...
- NPOI 中的公式列的值的获取
方法1 NPOI 中,对 sheet 对象设置 ForceFormulaRecalculation = true,即可实现自动将 Excel 的公式计算出来. 方法2 循环 Excel 的行.列,取出 ...