Python攻克之路-函数
Python 函数
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。
函数的特性:
1.减少重复代码
2.方便修改,更易扩展
3.保持代码一致性
函数名的命名规则(与变量规则一样)
a.函数名必须以下划线或字母开头,可以包含任意字母、数字或下划线的组合
b.不能使用任何的标点符号
c.函数名是区分大小写的
d.函数名不能是保留字(python内置的)
函数的创建
In [1]: def f(): ##定义函数,f是函数名,()可以用来传参 ...: print('ok') ##函数内容 ...: In [2]: f() ##调用函数,要写括号 ok In [4]: print(f) ##只写一个f是一个变量,变量指向的内存地址(print('ok')) <function f at 0x7f6c730508c8>
函数传参数
一个参数
In [3]: def f(index): ...: print('function %s'%index) ##传参,实现动态打印的效果 ...: In [4]: f(4) function 4 In [5]: f(5) function 5
两个参数:按顺序对应
In [1]: def add(x,y): ##形式的参数,定义时使用形参 ...: print(x+y) In [2]: add(4,5) ##实际参数,调用时使用实参 9 In [7]: def add(b,a): ...: print(a) ...: print(b) In [8]: add(7,5) 5 7
使用函数实现日志记录(在没有使用日志记录模块的情况下)
描述:定义的def只是存储在内存中,没有真正执行,当执行action时,会传入参数1时,就执行def action1(1)里面的内容,再调用logger(1)
[root@zabbix day14]# cat log-function.py #!/usr/local/python3/bin/python3 def action1(n): print('starting action1..') with open('log-record','a') as f: f.write('end action%s\n'%n) def action2(n): print('starting action2..') with open('log-record','a') as f: f.write('end action%s\n'%n) def action3(n): print('starting action3..') with open('log-record','a') as f: f.write('end action%s\n'%n) action1(1) action2(2) action3(3) [root@zabbix day14]# python3 log-function.py starting action1.. starting action2.. starting action3.. [root@zabbix day14]# cat log-record end action1 end action2 end action3
优化:把日志调用提炼成函数,并记录时间
[root@zabbix day14]# cat log-function.py #!/usr/local/python3/bin/python3 import time ##时间模块 def logger(n): time_format = '%Y-%m-%d %X' current_time = time.strftime(time_format) with open('log-record','a') as f: f.write(current_time) f.write(' end action%s\n'%n) #或者 f.write('%s end action%s\n'%(current_time,n))使用占位符 def action1(n): print('starting action1..') logger(n) def action2(n): print('starting action2..') logger(n) def action3(n): print('starting action3..') logger(n) action1(11) action2(22) action3(33) [root@zabbix day14]# python3 log-function.py starting action1.. starting action2.. starting action3.. [root@zabbix day14]# cat log-record 2018-03-12 13:38:04 end action11 2018-03-12 13:38:04 end action22 2018-03-12 13:38:04 end action33
函数的参数分类
必需参数:须以正确的顺序传入函数,调用时的数量必须和声明时的一样
In [1]: def f(name,age): ...: print('I am %s,I am %d'%(name,age)) In [2]: f('reid',2) I am reid,I am 2 In [3]: f('re',23) I am re,I am 23
关键字参数:(在实参增加)
In [6]: def f(name,age): ...: print('I am %s,I am %d'%(name,age)) In [7]: f(age=11,name='tom') I am tom,I am 11
默认参数:大多数情况下是固定值时就可以设定(在形参加)
[root@zabbix day14]# cat def.py
#!/usr/local/python3/bin/python3
def f(name,age,sex='male'): ##设置默认
print('Name: %s'%name)
print('Age: %d'%age)
print('Sex: %s'%sex)
f('tom',22)
f('tian',22)
f('lily',22,'female') ##特殊情况时给一个新值
[root@zabbix day14]# python3 def.py
Name: tom
Age: 22
Sex: male
Name: tian
Age: 22
Sex: male
Name: lily
Age: 22
Sex: female
不定长参数
In [8]: def add(*args): #*args取的是无命名参数 ...: print(args) In [9]: add(1,2,3) ##无命名参数 (1, 2, 3) ##放在元组 一个星号的:把无命名参数放在元组 [root@zabbix day14]# cat add.py #!/usr/local/python3/bin/python3 ##加法器 def add(*args): print(args) sum=0 for i in args: sum+=i print(sum) add(1,2,3,4) [root@zabbix day14]# python3 add.py (1, 2, 3, 4) 10
两个星号的:把不定长的键值对存在字典
注:不定长参数的位置args放在左边,有键值对的参数放在右边
In [10]: def info(*args,**kwargs): ...: print(args) ...: print(kwargs) ...: info('jerry',12,'male',job='it',hobby='eat') ...: ('jerry', 12, 'male') ##无命名在元组 {'job': 'it', 'hobby': 'eat'} ##键值对在字典
打印:遍历字典
[root@zabbix day14]# cat def.py #!/usr/local/python3/bin/python3 def f(*args,**kwargs): ##*args接收无命名参数,**kwargs接收有命名 for i in kwargs: ##键和值 print('%s:%s'%(i,kwargs[i])) f(job='it',hobby='running') ###键值对 [root@zabbix day14]# python3 def.py job:it hobby:running
不定长和默认参数的使用
关键字参数优先最高--》默认参数放左边--》*args--》**kwargs
默认参数放在左边,调用不加参数的情况
[root@zabbix day14]# cat def.py #!/usr/local/python3/bin/python3 def f(sex='male',*args,**kwargs): print(sex) for i in kwargs: print('%s:%s'%(i,kwargs[i])) f() ##调用时不传任何参数显示正常,sex='male'不是必须的,后两个参数是不定长的包括0,所以*args可以是空元组,**kwargs是空字典 [root@zabbix day14]# python3 def.py male
赋sex一个新值
[root@zabbix day14]# cat def.py #!/usr/local/python3/bin/python3 def f(sex='male',*args,**kwargs): print(args) ### for i in kwargs: print('%s:%s'%(i,kwargs[i])) f() f('female',1,2,34) f(1,2,34,'female') f(1,2,34,'female',name='jerry') [root@zabbix day14]# python3 def.py () (1, 2, 34) ##female和1,2,34一样,但是却没有被args接收,sex='male'占用一个位置,按必需参数的原则,但是按默认参数的原则sex='male' 应该要放在右边,否则会报错,但是这里*args,**kwargs有可能为空,所以sex占用了第一个位置后,它就直接对应female, (2, 34, 'female') #把female的位置调换后,1的值没有了,因为当传入1时,首先去找有没有对应的一个参数占用位置,而这里sex刚好占用这个位置, 剩下的就给无名参数所有 name:jerry #第三个,当传入name='jerry'时,它会自动执行for循环打印有名参数
函数的return
return:返回什么,给谁?
作用:a.结束函数 b.返回对象
不写,默认是return none,返回的内容自定义,返回的内容给调用者f()
In [1]: def f(): ...: print('ok') ...: return 10 ...: f() ...: ok Out[1]: 10 In [2]: def add(*args): ...: sum=0 ...: for i in args: ...: sum+=i ...: print(sum) ...: return sum ##返回一个值,再做下一步操作 ...: add(2,3) ...: 5 Out[2]: 5
如果return多个对象,那么Python会把多个对象封装成一个元组返回
In [3]: def f(): ...: return 1,2,[12,3] ...: f() ...: Out[3]: (1, 2, [12, 3])
函数的作用域****
作用域分为4种情况:
L: local,局部作用域,即函数定义的变量
E: enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的
G: globa,全局变量,就是模块级别定义的变量
B: built-in,系统固定模块里面的变量,比如int,bytearray等,搜索变量的优先级顺序依次是:
作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB
场景:
In [1]: if True: ##if中没有作用域 ...: x=3 ...: print(x) ...: 3 In [2]: def f(): ##在函数中,定义一个值没有被执行,因为函数中有作用域 ...: a=10 ...: f() NameError: name 'a' is not defined
LEGB例子:
int:是函数,把2.9的浮点型转换成整型,x就为2,内置的
[root@zabbix day14]# cat func.py #!/usr/local/python3/bin/python3 x = int(2.9) f_count = 3 #global def outer(): f_count = 2 #enclosing print(f_count) def inner(): f_count = 1 #local print(f_count) inner() outer() print(f_count) [root@zabbix day14]# python3 func.py 2 1 3
局部作用域默认不能修改全局作用域的值
[root@zabbix day14]# cat func1.py #!/usr/local/python3/bin/python3 count = 10 ##全局已经定义 def outer(): print(count) ##局部没有定义,直接使用全局的变量,那么再使用count=4就等于修改全局变量的操作 count=4 ##当print(count)时就表明是找全局,所以count=4相当于修改全局变量的值(或者count+=1是一样修改,count=count+1,首先会去找全局的count=10,再加1,再赋值给count,变成count=11),但是把print(count)注释可以,实际上是重新创建发个变量count=4,和全局的变量count的名称一样而已 outer() [root@zabbix day14]# python3 func1.py UnboundLocalError: local variable 'count' referenced before assignment #最后的错实际是count=4应该定义在print(count)之上才可以,因为当count=10时,这个错误还是会报证明,print(count)时是在def counter()里面找的
通过声明全局变量来修改全局变量
没有声明的情况:
[root@zabbix day14]# cat func1.py #!/usr/local/python3/bin/python3 count = 10 def outer(): print(count) count=4 print(count) outer() [root@zabbix day14]# python3 func1.py UnboundLocalError: local variable 'count' referenced before assignment
声明的情况:
[root@zabbix day14]# cat func1.py #!/usr/local/python3/bin/python3 count = 10 def outer(): global count ##声明 print(count) count=4 print(count) outer() [root@zabbix day14]# python3 func1.py 10 4
变量在enclosing层
[root@zabbix day14]# cat func2.py #!/usr/local/python3/bin/python3 def outer(): count=10 ##enclosing def inner(): nonlocal count count = 20 print(count) inner() #print(count) outer() [root@zabbix day14]# python3 func2.py 20
Summary:
(1)、变量查找的顺序:LEGB
(2)、只有模块、类、及函数才能引入新的作用域
(3)、对于一个变量,内部作用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部作用域的变量
(4)、内部作用域要修改外部作用域变量的值时,全局要使用global关键字,嵌套作用域变量要使用nonlocal
关键字.nonlocal是python3新增的关键字,有了这个关键字,就能完美的实现闭包了