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 # # 不光可以传递变量,还 ...
随机推荐
- PDO 增删改查封装的类
Selecting Data 你在mysql_*中是这样做的 <?php $result = mysql_query('SELECT * from table') or die(mysql_er ...
- 入门GTD时间管理系统必读
让我们从什么时间管理开始.什么是时间管理呢?嗯,时间管理就是管理时间.可是,时间怎么能够管理呢? 其实我们管理地并不是时间,而是我们做的事.我们将事情分配到合适的时间段中,在有限的精力中完成它们,得到 ...
- ZH奶酪:PHP 执行时间Fatal error: Maximum execution time of...
来源:http://stackoverflow.com/questions/5164930/fatal-error-maximum-execution-time-of-30-seconds-excee ...
- CMUSphinx Learn - Basic concepts of speech
Basic concepts of speech Speech is a complex phenomenon. People rarely understand how is it produced ...
- JAVA开发总结
1.Float取整 long warning; float fwarning = 0f; fwarning = total*0.34/100; warning = new Float(fwarning ...
- BFC特性 形成BFC
1.示例代码 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <ti ...
- window批处理杀死指定端口进程
@echo off setlocal enabledelayedexpansion set /p port=请输入端口号: for /f "tokens=1-5" %%a in ( ...
- Java关闭Socket来终止线程
Java代码: package Threads; import java.io.BufferedReader; import java.io.IOException; import java.io.I ...
- Aggressive cows
总时间限制: 1000ms 内存限制: 65536kB 描述 Farmer John has built a new long barn, with N (2 <= N <= 100,00 ...
- C语言清空输入缓冲区
来源:http://blog.csdn.net/guanyasu/article/details/53153705 https://zhidao.baidu.com/question/5241738. ...