【●】函数基础
一、创建函数
◆ 函数的定义及优点?
把实现一定功能的代码封装在一起 定义个名称 可以重复使用。
1.def语句
● 函数用def语句创建,
● 标题行由def关键字,函数的名字,以及函数的集合(如果有的话)组成。
● def子句的剩余部分包括了一个虽然可选但是强烈推荐的文档字串,和必须的函数体。
def 函数名():
函数体
2.前向引用——先定义后调用
● 函数不允许在函数未声明之前对其进行引用或者调用
[root@dc python]# vim hs1.py
#函数之间可以相互调用,但要先定义后调用
def bar():
print("this is function bar()")
def foo():
print("this is function foo")
bar() #没有定义过名称为bar()函数
foo()
[root@dc python]# python3 hs1.py
this is function foo
this is function bar()
二、调用函数(先定义后调用)
1.函数操作符
● 使用一对圆括号()调用函数,如果没有圆括号,只是对函数的引用
● 任何输入的参数都必须放置在括号中。
>>> def foo():
... print('Hello world')
...
>>> foo()
Hello world
>>> foo
<function foo at 0x7f214fe2d598>
>>>
2.给函数传参,
方式一:位置传参,参数的个数和位置必须一致
[root@dc python]# vim hs2.py
def sayinfo(name,age):
print(f"我的名字叫{name}年龄{age}岁")
#sayinfo() #错误
#sayinfo("bob") #错误
#sayinfo(21,"jerry") #错误
sayinfo("zyl",20) #正确
2.1关键字参数
● 关键字参数的概念仅仅针对函数的调用
● 这种理念是让调用者通过函数调用中的参数名字来区分参数。
● 这样规范允许参数缺失或者不按顺序
方式二:关键字传参,与位置无关,但个数要一致。
def sayinfo(name,age):
print(f"我的名字叫{name}年龄{age}岁")
sayinfo(20,"name=zyl") #正确
3.参数组传参:函数的形参个数不固定(形参个数可能是0也可能是多个时候使用)
● Python允许程序执行一个没有显示定义参数的函数(个数不固定)
● 相应的方法是通过一个把元组(非关键字参数)或字典(关键字参数)作为参数组传递给函数
◆ 使用元组接收
def sayinfo(*args):
pass
def sayinfo(*args):
print("变量args的值是",args)
print("#" * 20)
sayinfo() #没有传参 空元组
sayinfo(9,8) #传了一个参数 元组有一个元素
sayinfo("a","d",12,3,46) #传了5个参数 元组有5个参数
[root@dc python]# python3 hs3.py
变量args的值是 ()
####################
变量args的值是 (9, 8)
####################
变量args的值是 ('a', 'd', 12, 3, 46)
####################
#编写函数very_sum()计算任意个数相加的和
def very_sum(*x):
s = 0 #定义一个变量存储累加的和
i = 0 #定义循环的初始值
while i < len(x):
s += x[i]
i += 1
print(s)
very_sum()
very_sum(2)
very_sum(3,9)
very_sum(5,9,12,23)
[root@dc python]# python3 hs3.py
0
2
12
49
◆ 使用字典接收
[root@dc python]# vim hs4.py
def sayinfo(**kwargs):
pass
#def sayinfo(name,age,gender):
# print("名字%s年龄%d性别%s" %(name,age,gender))
#sayinfo(name="zyl",age=21)
def sayinfo(**kwargs):
print(kwargs)
sayinfo()
sayinfo(gender='男',name='zzb')
sayinfo(name='yys',gender='女',school='达内')
[root@dc python]# python3 hs4.py
● 综合案例
def sayinfo(x,y,*args,school="tarena",**kwargs):
print(x,y,school)
print(args)
print(kwargs)
print("*" * 20)
#没有对应的数据都会被后边的 元组变量 或字典变量接收
sayinfo(9,8,"a","f","bob",school="beijing",name="yaya",classname="nsd2103" )
#没有传参 元组变量 或字典变量就没有元素 创建的是空元组和空字典
sayinfo(9,8)
[root@dc python]# python3 hs4.py
9 8 beijing
('a', 'f', 'bob')
{'name': 'yaya', 'classname': 'nsd2103'}
********************
9 8 tarena
()
{}
********************
三、匿名函数
1.lambda
● Python允许用lambda关键字创造匿名函数
● 匿名是因为不需要一标准的def方式来声明
● 一个完整的lambda“语句”代表了一个表达式,这个表达式的定义体必须和声明放在同一行
● 功能是简化代码 创建没有名字的函数
1.2格式
变量名 = lambda 参数列表:函数功能体
def bdx(x , y):
if x > y:
print(f"数字{x}大于数字{y}")
else:
print(f"数字{y}大于数字{x}")
#bdx(100,99)
#bdx(63,50)
#lambda创建匿名函数的格式 lambda 参数列表: 函数体
DX = lambda x,y:print(f"{x} > {y}" ) if x > y else print( f"{y} > {x}")
DX(10,9)
DX(11,19)
####################
#不加()是对函数的引用 相当于 把代码复值给了对方
def bdx(x , y):
if x > y:
print(f"数字{x}大于数字{y}")
else:
print(f"数字{y}大于数字{x}")
#bdx(99,68)
print(bdx)
x=bdx #不加()是对函数的引用 相当于 把代码复值给了对方
print(x)
print("+" * 10)
x(99,68)
【●】函数高级应用
一、变量作用域
变量的作用域 ,在脚本里定义函数的时候,变量分为全局变量和局部变量2种。
1.全局变量:
◆ 在所有函数的上方定义的变量 , 是脚本列定义的所有函数都可以使用的变量。
● 标识符的作用域是定义为期声明在程序里的可应用范围,也就是变量的可见性。
● 在一个模块中最高级别的变量有全局作用域
● 全局变量的一个特征是除非被删除掉,否则他们能存活到脚本运行结束,且对于所有函数,它们的值都是可以被访问的。
2.局部变量
◆ 在每个函数体内部定义的变量,只能函数自己使用,只在函数执行过程中有效。
● 局部变量只是暂时地存在,仅仅只依赖于定义他们的函数现阶段是否处于活动
● 当一个函数调用出现时,其局部变量就进入声明它们的作用域。在那一刻,一个新的局部变量名为那个对象创建了。
● 一旦函数完成,框架被释放,变量将会离开作用域。
● 如果局部变量与全局变量有相同名称的变量,那么函数运行时,局部变量的名称将会把全局变量名称遮盖住。
3.global语句
● 因为全局变量的名字能被局部变量给遮盖掉,所以为了明确地引用一个已命名的全局变量,必须使用global语句。
global 关键字 在函数体内调用全局变量
name = "jerry"
age = 19
def a():
#name="bob"
global name , age
name="bob"
age = 21
print("fun a name values:", name,age)
def b():
print("fun b name values:", name,age)
def c():
print("fun c name values:", name)
a()
print("+++++")
b()
print("+++++")
c()
在脚本里写一个函数 tj 执行脚本时能够输出函数被执行的次数
vim test.py
num = 0
def tj(name):
print("你输入的名字是",name)
global num
num += 1
tj("bob")
tj("tom")
tj("plj")
print("函数tj 被执行了%d 次"%num)
[root@teacher code]# python3 test.py
你输入的名字是 bob
你输入的名字是 tom
你输入的名字是 plj
函数tj 被执行了3 次
[root@teacher code]#
二、函数式编程
● return的使用
让函数执行后,有数据返回,默认返回值是None。
#return返回值的案例
]# vim funa.py
def qh(i,j):
i += 1
j += 1
print(i,j)
# return None 返回值默认为空
return i,j #函数遇到return就结束执行,所以一般返回值放在功能体代码的最后
一行执行。
v1 = qh(1,2)
print("v1 values :", v1)
]# python3 funa.py
2 3
v1 values : (2, 3)
1.偏函数
● 指的是编程思维,高度抽象的编程范式;用一系列函数来解决问题。
● 高阶函数是偏函数编程的体现,把函数作为参数传入,这样的函数称为高阶函数。
● 偏函数的概念是将函数数式编程的概念和默认参数以及可变参数结合在一起。
● 一个带有多个参数的函数,如果其中某些参数基本上固定的,那么就可以通过偏函数为这些赋默认值。
◆使用函数来解决问题
>>> sum([1,2,3,4,5]) #sum() 求和的函数
15
>>> sum(range(1,6))
15
>>> min([15,54,76,47])
15
>>> max([15,54,76,47])
76
>>>
>>> x=sum # 把sum赋值给 x ,x就有求和的功能 ,函数名也是变量 存储的是功能代码
>>> print(x(range(1,11)))
55
>>>
2.高阶函数
2.1 filter()函数 # 中文意思过滤
● filter(func,seq):调用一个布尔函数func来迭代遍历每个序列中的元素;返回一个使func返回值为true的元素的序列
● 如果布尔函数比较简单,直接使用lambda匿名函数就显得非常方便了
● 功能:过滤列表,过滤掉不符合条件的函数,返回一个filter对象使用list()转换为列表。
>>> L1=list(range(1,11))
>>> L1
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> def fun(x):
... return x % 2 == 0
...
>>> fun(10)
True
>>> filter(fun,L1)
<filter object at 0x7f33048cc198>
>>> a=filter(fun,L1)
>>> print(list(a)) #过滤10以内的偶数
[2, 4, 6, 8, 10]
>>>
>>> data = filter(lambda x: x % 2, [num for num in range(10)])
>>> print(list(data)) #过滤出10以内的奇数
[1, 3, 5, 7, 9]
2.2 map()函数
● map(func,seq):调用一个函数func来迭代遍历每个序列中的元素;返回一个经过func处理过的元素序列。
● 如果布尔函数比较简单,直接使用lambda匿名函数就显得非常方便了
● 功能:把函数作用到列表的每个元素上,并将结果组成新的迭代器返回
◆ 给列表中每个元素值+1
>>> def fun(x):
... return x + 1
...
>>> fun(1)
2
>>> L= list(range(1,11))
>>> L
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> A=map(fun,L)
>>> print(list(A))
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>>
3.生成器
● 从语句上讲,生成器是一个带yield语句的函数。
● 一个函数或着子程序只返回一次,但一个生成器能暂停执行并返回一个中间的结果。
● yield语句返回一个值给调用者并暂停执行。
● 当生成器的next()方法被调用的时候,它会准确的从离开的地方继续。
● 与迭代器相似,生成器以另外的方式来运作。
● 当到达一个真正的返回或者函数结束没有更多的值返回,Stoplteration异常就会被抛出。
● yield 功能: 返回一个值,并记住返回值的位置,下次迭代就从这个位置后开始。
[root@localhost ~]# vi yl.py
def fun():
print("123")
print("123123")
yield 555
print("*" * 10)
print("456")
print("456456")
yield 666
print("#" * 10)
g = fun() #创建生成器对象g
# 可以先注释掉后2次 执行 只执行第1次 效果更明显
v1 = next(g) #第1次执行生成器
print(v1)
v2 = next(g) #第2次执行生成器
print(v2)
#第3次执行 没有数据会报错
v3 = next(g)
print(v3)
[root@localhost ~]# python3 yl.py
123
123123
555
**********
456
456456
666
##########
Traceback (most recent call last):
File "yl.py", line 21, in <module>
v3 = next(g)
StopIteration
[root@localhost ~]#
● 在循环结构里 next() 会自动被执行
[root@localhost ~]# cat yl2.py
def fun():
print("123")
print("123123")
yield 555
print("*" * 10)
print("456")
print("456456")
yield 666
print("#" * 10)
g = fun() #创建生成器对象g
for i in g: #会把函数里yield的返回值赋值给 i
print(i)
[root@localhost ~]# python3 yl2.py
123
123123
555
**********
456
456456
666
##########
[root@localhost ~]#
● 生成器例子
# 把数据1-20 每10个数 为1组 保存到列表La
[root@teacher code]# cat list20.py
def fun(str,end):
L = []
i = str
while i <= end:
L.append(i)
if i % 10 == 0:
yield L
L = []
i += 1
###########################
la = []
for data in fun(1,20):
la.append(data)
print(la)
print("-" * 20)