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新增的关键字,有了这个关键字,就能完美的实现闭包了

浙公网安备 33010602011771号