一、函数的作用
1、减少重复代码
2、方便修改,可扩展性
3、保持代码的一致性
二、函数的命名
1、函数命名表现出其作用,以下划线或者字母开头,不能以数字开头
2、区分大小写
3、不能是保留字
三、形参、实参
1、必需的参数须以正确的顺序传入函数,调用时的数量必须和声明时一样
2、关键字参数,即传入的时候把形参放在前边,传入实参值eg: def f(a,b) 调用 f(a='1',b=2)
3、默认参数值,传入默认参数的值必须在没有赋默认值的参数后边eg: def f(a, b, c=0)
4、不定长参数:需要一个函数处理比当初声明时更多的参数,叫做不定长参数,声明时不命名(没有形参名字)。
def f(*args, **kwargs)
# 传入的是元祖
def add(*args):
print(args)
sum = 0
for i in args:
sum =+ i
print(sum)
add(1)
# 传入的是字典
def print_info(**kwargs):
for key in kwargs:
print("{key} is {value}".format(key=key, value=kwargs.get(key)))
print_info(name='jiangqijun', age='18')
#所以像没有名字的被args接收,有名字的被kwargs接收,即直接传入字符、int数据、列表、元祖则被args接收,而name='jiangqijun',被kwargs接收
非常重要:
传入规则:关键参数优先级最高放在最左边,再者就是默认参数,再者是*args,最后是**kwargs。
a.传入的时候要按照顺序来,所以要有命名和无命名的区分。否则报错。
eg:f(1, name='jiangqijun', 2)
def(*args, **kwargs)
s1 = 's1'
s2 =2
s3 = True
s4 = bytes('s4', encoding='utf-8')
s5 = [5,6]
s6 = (6,7)
s7 = {'s7':'7'}
s8 = {'p8'}
1、 def f(*args):
print(args)
传入s1至s8,如果不带任何*调用,接收后每个变量作为元组的一个元素
f(s1,s2,s3,s4,s5,s6,s7,s8)
#('s1', 2, True, b's4', [5, 6], (6, 7), {'s7': '7'}, {'p8'})
2、def f(*args):
print(args)
传入s1至s8,如果带*调用,接收后每个变量里面的每个小的元素作为元组的一个元素
f(*s1,*s5,*s6,*s7,*s8) 注意这里,*后面只能传入可迭代对象,否则报错,字符串是可迭代对象,但是会被拆开成每个字符
#('s', '1', 5, 6, 6, 7, 's7', 'p8')
3、
def f1(**kwargs):
print(kwargs)
对于**只能调用可map的对象即 f1(**s7),否则报错,不能f1(s7)调用.
当存在def f1(*args,**kwargs) 时 一定要加**才能正常调用到 f1(**s7)
b.传入的时候*args必须在左边,**kargs必须在右边否则报错
eg:def f(**kwargs,*args)
c.def f(sex='female', *args, **kwargs):这里先给的是默认值,再者是分给args再者给kwargs
def f(sex='female', *args, **kwargs):
print(sex)
print(args)
print(kwargs)
f(1, 2,7,'hello',name='jiangqijun')
结果是:
1
(2, 7, 'hello')
{'name': 'jiangqijun'}
补充
def f1(*args):
print(args)
l = [1, 2, 3]
f1(l)#这种得到的结果是([1, 2, 3],)
f1(*l)#这种得到的结果是(1, 2, 3)
def f2(**kwargs):
print(kwargs)
d = {'name':"jiangqijun"}
#f2(d)#报错
f2(**d)#{'name': 'jiangqijun'}
四、return
#1、如果没有添加return则默认返回一个none 2、结束函数 3、返回某个对象
def f():
print('hello')
return
#4、如果返回的是多个对象则将多个对象封装为元祖返回
def f2():
return 'a',4,[1,7]
五、作用域
能够开拓作用域的有类、模块、函数,其他的如if,for,try 不引入作用域模块.
|
这个是没有问题的,if并没有引入一个新的作用域,x仍处在当前作用域中,后面代码可以使用。
1 2 3 |
|
def、class、lambda是可以引入新作用域的。
#作用域
# 1、L local ,局部作用域,函数中定义的变量
# 2、E enclosing 嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的
# 3、G global,全局变量,就是模块级别定义的变量
# 4、B built_in,系统固定模块里边的变量,比如int bytearray
#搜索顺序是:local>enclosing>global>built-in
b_var = int(8.9) #这里的int函数是built-in变量
g_var = 6 #这里是全局变量
def outer():
e_var = 5 #嵌套变量
def inner():
l_var = 2 #本地变量
#a.此处前边已经使用过count,所以后边不能对全局变量进行修改,报错。这里报错的原因是调用test的时候代码全部
#加载到内存,print(count)找到下面的局部变量count,所以报错count使用应该在声明之后
count = 2
def test():
print(count)
count=1
test()
#b.此处函数里的count是一个新的count
count = 2
def test():
count=1
print(count)
#c.通过一个关键字global声明进行修改
count = 2
def test():
global count
print(count)
count=1
print(count)
#d.通过关键字nolocal修改嵌套变量
def outer():
e_var = 5 #嵌套变量
def inner():
nonlocal e_var
print(e_var)
l_var = 2 #本地变量
e_var=3
print(e_var)
inner()
outer()
小结:
(1)变量查找顺序:LEGB,作用域局部>外层作用域>当前模块中的全局>python内置作用域;
(2)只有模块、类、及函数才能引入新作用域;
(3)对于一个变量,内部作用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部作用域的变量;
(4)内部作用域要修改外部作用域变量的值时,全局变量要使用global关键字,嵌套作用域变量要使用nonlocal关键字。nonlocal是python3新增的关键字,有了这个 关键字,就能完美的实现闭包了。
六、高阶函数
# 高阶函数
#1、函数名称就是一个变量,里边的指向代码块,函数名可以赋值给其他变量
#2、函数名可以作为函数参数
#3、函数名作为函数的返回值eg.foo3(),如果return inner()则会调用,如果是return inner则只返回一个变量
# def func(n):
# return n*n
#
#
# def foo(a, b, f):
# print(func(a)+f(b))
#
# foo(1, 2, func)
# def foo3():
# def inner():
# return 3
# return inner
#
# print(foo3()) #返回的是inner的对象地址
定义:既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
一个最简单的高阶函数:
def add(x, y, f):
return f(x) + f(y)
七、递归函数
递归函数的优点: 是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
递归特性:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返 回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。)
def count(n):
if n < 1:
return -1
elif n == 1:
return 1
return n*count(n-1)
八、内置函数
#1、eval传入的参数locals()则只能用函数内部的,传入的参数globals()则使用全局变量,这里表示等与x+y
# x = '1'
# y = '2'
# def test():
# x = 2
# y = 3
# num1 = eval('x+y')
# print(num1)
# num2 = eval('x+y', globals())
# print(num2)
# test()
#2、filter()用作过滤,传入的是函数和迭代器,里边加的函数必须包含判断条件,使用filter得到的是一个迭代器对象。需要其他函数进行强制转换
# def test(s):
# if s!='a':
# return s
#
# s = 'abcd'
# result = filter(test, s)
# print(list(result))
#3、map()方法,传入的是函数和迭代器,返回的是一个迭代器,需要其他函数进行强制转换
# def test(n):
# return n*n
# result = map(test, [1,2,3])
# print(list(result))
#4、reduce() 传入函数和一个迭代器,这里表示先传入1,2得到结果3再传入3,3,以此类推
# def test(x, y):
# res = x + y
# return res
#
# l = [1, 2, 3, 4, 5, 6, 7]
# print(reduce(test, l))
#5、lambda 命名规则是,在左边传入函数的参数,冒号右边传入函数的返回值,创建时没有名字所以叫做匿名函数
# add = lambda x,y:x+y
# print(add(1,2))