Python之路-函数基础&局部变量与全局变量&匿名函数&递归函数&高阶函数

时间:2024-03-26 17:34:03

一、函数的定义与调用

  函数:组织好的、可重复使用的、用户实现单一或者关联功能的代码段。函数能够提高应用的模块性和代码的重复利用率。Python提供了很多内置的函数,比如len等等,另外也可以根据自己的业务需求进行用户自定义函数的创建。

  函数的定义规则

  函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。 任何传入参数和自变量必须放在圆括号中间。 函数的第一行语句可以选择性地使用文档字符串---用于存放函数说明。 函数内容以冒号起始,并且缩进。

  定义一个函数

  def 函数名([参数列表]): #参数列表可选项 函数体

  调用函数

  Python内置了很多函数,内置函数可以直接调用。调用一个函数需要知道函数的名称和函数的参数。

  语法:函数名([参数列表])

  另外:函数名其实就是指向一个函数对象的引用,完全可以把函数名赋值给一个变量,相当于给这个函数起了一个别名

'''
函数:组织好的,可以重复使用的,用户实现单一或者关联功能的代码段
提高应用的模块性和代码的重复使用
''' '''
函数的定义:
def 函数名([参数])
函数说明
要封装的代码块
''' # def Pname(): #不放参数
# '''
# 获取姓名
# '''
# print('大家好我是熊爱明同学') '''
调用
'''
# Pname()
# pri = Pname #将函数名赋值给另外一个变量 相当于取一个别名
# pri() # def getNum():
# print(190) #调用
# getNum()

二、函数参数

  形参和实参

'''
实参和形参
'''
# def Pname(userName): #userName形参
# '''
# 获取姓名
# :param userName:
# :return:
# '''
# print('大家好我是%s同学!' %userName) # Pname('刘德华') #传递了实参

  函数参数分类

    必备参数

    关键字参数

    默认参数

    不定长参数

  函数参数--必备参数

  函数定义中允许拥有多个形参,因此函数在调用的时候,也可能包含多个实参。向函数传递参数的方式有很多,通过实参和形参的顺序对应,这就是位置实参。只有位置一致,才能被正确匹配。位置实参是最简单也最常用的关联方式。

#必备参数
# def getInfo(name,address):
# print('大家好我叫%s,我来自%s' %(name,address)) #顺序 个数 要一致
# getInfo('刘德华','香港')

  函数参数--关键字参数

  关键字实参是传递给函数的名称-值对。直接在实参中将名称和值关联起来,因此向函数传递实参时不会混淆。函数调用使用关键字参数来确定传入的值。使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值.

#关键字参数
# def getInfo(name,address):
# print('大家好我叫%s,我来自%s' %(name,address)) #给实参加上关键字 关键字对应形参
# getInfo(address='香港',name='刘德华')
# getInfo(name='刘德华','香港')#要使用关键字就必须统一都使用

  函数参数--默认参数

  函数定义的时候,设置的参数是形参。那么也可以给每个形参指定一个默认值。当调用函数时,如果没有传入实参,就使用形参的默认值。如果调用的时候传入了实参,那么程序将使用传入的实参。

#默认参数
# def getInfo(name,address = '香港'): #默认值参数,就是在声明函数的时候给参数赋值 声明默认值的一般放在最后面
# print('大家好我叫%s,我来自%s' %(name,address)) # getInfo('刘德华')#有默认值就不需要传递
# getInfo('刘德华','九龙') #指定传递参数的话会覆盖原来默认值

  函数参数--不定长参数

  有时可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数。

#不定长参数
# def getInfo(name,address,*args,**args2):
# print('大家好我叫%s,我来自%s' % (name, address))
# print(args) #() args是一个元组类型 ('a', 'b', 'g', 'd')
#*args 是接受所有未命名的参数(关键字) (一颗星)
# print(args2) # args2 字典数据类型 {'age': 18}
#**args2 是接受所有命名的参数 (带关键字的) (两颗星)
# getInfo('刘德华','九龙','a','b','g','d',age = 18)

  注意:加了星号(*)的变量名会存放所有未命名的变量参数。加了(**)会存放所有命名的变量参数

  可变对象与不可变对象的传递

  在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict,set等则是可以修改的对象。

  不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。

  可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了

  区别:

  不可变对象,传递的是对象的值,不是对象本身,如果修改值,修改的是另一个复制的对象,不会影响原来对象的本身

  可变对象,传递对象自己。函数内部如果修改值会影响对象本身。

'''
可变对象与不可变对象的传递
'''
#标记函数
def sign():
print('_'*50) # #值传递 不可变对象的传递
# def fun (args):
# args = 'hello' #重新赋值
# print(args) #输出hello
#
# str1 = 'baby' #声明一个字符串变量 不可变数据类型
# fun(str) # 将该字符串传递到函数中
# sign()
# print(str1) #引用传递 可变对象的传递
# def fun (args):
# args[0] = 'hello' #重新赋值
# print(args)
#
# list01 = ['baby','come on'] #声明一个列表 可变数据类型
# fun(list01) # 将该列表传递到函数中
# sign()
# print(list01) #['hello', 'come on'] 传递的是队形本身 函数里面修改了值 原对象也会跟着修改

  函数参数--可变对象与不可变对象(传递的时候)

  不可变类型:如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。

  可变类型:如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响

三、函数返回值

  返回值:

  函数并非总是将结果直接输出,相反,函数的调用者需要函数提供一些通过函数处理过后的一个或者一组数据,只有调用者拥有了这个数据,才能够做一些其他的操作。那么这个时候,就需要函数返回给调用者数据,这个就被称之为返回值,想要在函数中把结果返回给调用者,需要在函数中使用return。

  return语句用于退出函数,选择性的向调用者返回一个表达式。直接return的语句返回None。

Python之路-函数基础&局部变量与全局变量&匿名函数&递归函数&高阶函数

注意:return后语句不再执行。

  接收返回值

  可以将函数的返回值保存在变量中

  Return和print区别

  print是将结果输出到控制台,return语句结束函数的调用,并将结果返回给调用者,且返回的结果不能输出到控制台(也就是不能直接打印出来)需要通过print才能打印出来

'''
函数的返回值
return关键字实现
''' # def max(x,y):
# if x > y:
# return x#结束函数的运行,并且将结果返回给调用的地方
# else:
# return y
# num = max(3,4) #声明一个num接受调用函数的返回值
# print(num) #return 返回多个返回值
# def tep(x,y):
# return x,y # num = tep(1,2) #元组形式接收
# num1,num2 = tep(1,2) #对应接收
# print(num)
# print(num1)
# print(num2)

  函数类型

  无参数,无返回值的函数

  无参数,有返回值的函数

  有参数,无返回值的函数

  有参数,有返回值的函数

  什么是yield

  yield 的作用就是把一个函数变成一个generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个生成器,如调用getnum函数,不会执行该函数,而是返回一个iterable迭代对象!

区别:与return类似,都可以返回值,但不一样的地方,yield可以返回多次值,而return只能返回一次。

  迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式。

   迭代器是一个可以记住遍历的位置的对象。

   迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。

   迭代器只能往前不会后退。 迭代器有两个基本的方法:iter() 和 next()。

  字符串,列表或元组,集合对象都可用于创建迭代器

'''
迭代器
什么是迭代对象:可以用for in 遍历的对象都可以叫做迭代对象 :Iterable
如:list string dict
迭代器:可以被next()函数调用的并不断返回下一个值的对象就叫做迭代器:Iterator ''' # list01 = [1,2,3,4]
# print(next(list01)) #'list' object is not an iterator #通过iter()将一个可迭代的对象编程迭代器
# a = iter(list01)
# print(a) #list_iterator object at
# print(next(a))
# print(next(a))
# print(next(a))
# for i in a :
# print(i)

  生成器(generator)

  使用了 yield 的函数被称为生成器。

  跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

  在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次从当前位置继续运行。

  注意:可以通过for循环或者手动调用getNum(5)的next() 方法

'''
yield 生成器
生成一个迭代器
作用是将一个函数变成一个generator
使用生成器 可以达到延迟操作的效果
就是指在需要的时候产生结果 节省资源消耗 和声明一个序列不同的是生成器在
不适用的时候几乎是不占内存的
'''
# def getNum(n):
# i = 0
# while i <= n:
# # print(i)
# # return i #返回一个i 结束函数的运行
# yield i #将函数变为generator <generator object getNum at 0x00000000006DA258>
# i += 1
#调用
# getNum(5)
# print(getNum(5)) #返回0 # a = getNum(5) #把生成器赋值给一个对象
#通过next方法使用迭代器
# print(next(a)) #输出yield返回值
# print(next(a)) # for i in a: #使用for循环遍历迭代器
# print(i) #
# a = [x for x in range(10000)]
# print(a) # a = (x for x in range(10000)) #这里是一个生成器 没有元组推导式
# print(a) #产生迭代器
# print(next(a))

  生成器-send(generator)

  a = yield 1 这个表达式,如果这个表达式只是x = 1,相信每个人都能理解是把1的值赋值给了x.

  而现在等号右边是一个yield 1,所以先要执行yield 1,然后才是赋值.

  yield把1值返回到了调用者那里,因为执行等号右边的yield就是暂停,所以不会对a赋值 那这个表达式的下一步操作:赋值

  换句话说a = yield 1 只执行了一半 而send()里面的值的作用是把值传进当前的yield.

'''
send
'''
# def gen():
# i = 0
# while i < 5:
# temp = yield i #使用了yield之后是一个生成器 #这里是赋值吗? 不是
# print(temp)
# i += 1
# a = gen()
# print(next(a)) #<generator object gen at 0x000000000097A258>
# print(next(a))
# print(a.send('我是a')) #可以将值发送到上一次yield的地方 赋值给 temp =

  四、变量的作用域

  一个程序的所有的变量并不是在哪个位置都可以访问的。访问权限决定于这个变量是在哪里赋值的。

  变量的作用域决定了在哪一部分程序你可以访问哪个特定的变量名称。

  两种最基本的变量作用域如下:

    全局变量

    局部变量

  定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

  可变类型的全局变量

  对于不可变类型的全局变量来说,要在函数中修改需要global声明

  对于可变类型的全局变量来说,要在函数中修改可以不使用global声明

  局部变量

  局部变量,就是在函数内部定义的变量

  不同的函数,可以定义相同的名字的局部变量,但是各用个的不会产生影响

  全局变量

  全局变量是声明在函数外部的变量,定义在函数外的拥有全局作用域

  修改全局变量

  global关键字 要想在函数内部修改全局变量需要使用grobal关键字声明。

'''
变量作用域
''' #局部变量:声明在函数内的变量 # def test1():
# a = 1
# print(a)
# print(id(a))
#
# def test2():
# # a = 1
# print(a)
# print(id(a))
#
# test1()
# test2() #两个地址不一样 #全局变量 # def test1():
# print(a)
# print(id(a))
#
# def test2():
# print(a)
# print(id(a))
#
# a = 1 #作用于全局 整个文件
# test1()
# test2() #地址一样 '''
修改全局变量
''' # def test1():
# # a = 1 #声明的是一个局部变量
# print(a)
# print(id(a))
#
# def test2():
# global a
# a = 3
# print(a)
# print(id(a))
#
# a = 1
# test1()
# print(a)
# print(id(a))
# test2()

  五、匿名函数

  匿名函数:定义函数的过程中,没有给定名称的函数就叫做匿名函数;Python中使用lambda表达式来创建匿名函数。

  lambda 来创建匿名函数规则。

  ●lambda只是一个表达式,函数体比def简单很多。

  ●lambda的主体是一个表达式,而不是一个代码块,所以不能写太多的逻辑进去。

  ●lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。

  ●lambda定义的函数的返回值就是表达式的返回值,不需要return语句块

  ●lambda表达式的主要应用场景就是赋值给变量、作为参数传入其它函数

  lambda匿名函数的表达式规则是:lambda 参数列表: 表达式

'''
匿名函数
lambda [参数]:表达式
默认会返回一个表达式
lambda函数里面不能包含for循环
不能换行
''' #么有参数的lambda表达式
# s = lambda : '哈哈哈' #通过lambda 声明一个匿名函数 赋值给s
# print(s()) #通过s调用匿名函数
#
# #有参数
# s = lambda x : x*2
# print(s(3))
#
# s = lambda x ,y: x+y
# print(s(3,2)) '''
矢量化的三元运算符
if 条件:
代码块
else :
代码块 '''
# s = lambda x,y: x if x > 2 else y
# print(s(2,3)) '''
字典排序 使用lambda
'''
# dic = {'a':1,'c':3,'b':2}
# dic.sort()#字典么有sort方法 #通过内置函数sorted进行排序
#内置函数有返回值
# dic = sorted(dic)
# print(dic)#返回一个列表['a', 'b', 'c']
# dic = sorted(dic.items())
# print(dic())#[('a', 1), ('b', 2), ('c', 3)]
# dic = sorted(dic.items(),reverse=True)
# print({k:v for k,v in dic})
# print(dic.items()) #dict_items([('c', 3), ('a', 1), ('b', 2)])
# dic = sorted(dic.items(),key = lambda x:x[1] ,reverse=True) #这里的x为('c', 3) 等等 x[1]取第二个元素
# print(dic)#[('c', 3), ('b', 2), ('a', 1)]
# print({k:v for k,v in dic})#{'c': 3, 'b': 2, 'a': 1} # list01 = [
# {'name':'joe','age':18},
# {'name':'susan','age':19},
# {'name':'Tom','age':17}
# ]#字典列表
# dic = sorted(list01,key = lambda x:x['age'],reverse=True)
# print(dic)

六、递归函数

  递归函数:递归就是子程序(或函数)直接调用自己或通过一系列调用语句间接调用自己,是一种描述问题和解决问题的基本方法。(一句话,自己调用自己)

'''
递归函数
''' # def main(n):
# print('进入第%d层梦境'%n)
# if n == 3:
# print('到达潜意识区,原来你是我最爱的人!开始醒来。')
# else:
# main(n+1)
# print('从第%d层梦境醒来'%n)
#
# main(1) #会带调用的地方
'''
第一次调用: 进入第1层梦境
第二次调用:进入第2层梦境
第三次调用: 进入第3层梦境 到达潜意识区,原来你是我最爱的人!开始醒来。
从第3层梦境醒来 结束第三次调用
从第2层梦境醒来 结束第二次调用
从第1层梦境醒来 结束第一次调用
''' '''
等价于
'''
# def main(n):
# print('进入第%d层梦境'%n)
# if n == 3:
# print('到达潜意识区,原来你是我最爱的人!开始醒来。')
# else:
# def main(n):
# print('进入第%d层梦境' % n)
# if n == 3:
# print('到达潜意识区,原来你是我最爱的人!开始醒来。')
# else:
# def main(n):
# print('进入第%d层梦境' % n)
# if n == 3:
# print('到达潜意识区,原来你是我最爱的人!开始醒来。')
# else:
# print('从第%d层梦境醒来' % n)
# print('从第%d层梦境醒来' % n)
# print('从第%d层梦境醒来'%n)
#
# main(1) '''
递归求阶乘
'''
# def jiecen(n):
# if n == 1:
# return 1
# else:
# return n*jiecen(n-1)
#
# print(jiecen(10))

七、内置函数与高阶函数

  常用内置函数

Python之路-函数基础&局部变量与全局变量&匿名函数&递归函数&高阶函数

Python之路-函数基础&局部变量与全局变量&匿名函数&递归函数&高阶函数

  常用高阶函数

'''
常用高阶函数
map(func,seq[seq[seq...]])->list
接收一个函数积多个集合序列,会根据提供的函数对指定的序列做映射,然后返回一个新的map
filter(func,seq)->list or tuple or string
用于过滤序列,过滤掉不符合条件的元素,返回由符合条的元素组成的filter对象
reduce(func,seq[,initvalue])
对序列中的所有元素调用func进行函数合并操作,可以给定一个初始值
'''
#map(func,seq[seq[seq...]])->list
# list01 = [1,2,3,4,5]
# list02 = [2,4,6,8,10]
# new_list = map(lambda x:x*2,list01)
# new_list = map(lambda x,y:x*y,list01,list02)
# print(new_list)#new_list是一个新的map对象 <map object at 0x000000000098C780>
# print(list(new_list))#map对象转化为list输出
# for i in new_list:
# print(i) #filter(func,seq)->list or tuple or string
# list02 = [2,4,6,8,10]
# new_list = filter(lambda x:x>4,list02)
# print(list(new_list))#[6, 8, 10] #reduce
from functools import reduce # list02 = [2,4,6,8,10]
# new_list = reduce(lambda x,y:x+y,list02)
# new_list = reduce(lambda x,y:x+y,list02,0)
# print(new_list) '''
案例
格式化用户的英文名,要求首字母大写,其他字母小写
将用户英文名,年龄,性别三个集合的数据结合到一起,形成一个算组列表
过滤性别为男的用户
求性别为男的用户的平均年龄
'''
name = ['joe','susan','black','lili']
age = [18,19,20,21]
sex = ['m','w','m','w'] #格式化用户的英文名,要求首字母大写,其他字母小写
new_name = map(lambda x:x.title(),name)
print(list(new_name))#['Joe', 'Susan', 'Black', 'Lili'] #将用户英文名,年龄,性别三个集合的数据结合到一起,形成一个算组列表
users = map(lambda x,y,z:(x,y,z),name,age,sex)
new_users = list(users)
print(new_users) #过滤出性别为男的用户()
new_users = filter(lambda x:x[2] == 'm',new_users)
new_users = list(new_users)
print(new_users) #求性别为男的用户的平均年龄
total_age = reduce(lambda x,y:x+y[1],new_users,0)
print(total_age/len(new_users))

Python之路-函数基础&局部变量与全局变量&匿名函数&递归函数&高阶函数

练习: 

'''
函数,计算传入字符串的个数
'''
# def getLen(s):
# if isinstance(s,str): #args1: 传入的数据 args2:数据类型
# return len(s)
# else:
# return '类型错误'
# # num = getLen('fsfhbkjk jfhgd')
# num = getLen(45986)
# print(num) '''
函数 判断用户传入的字符串、列表、元祖长度是否大于5
''' # def getLen2(args):
# if isinstance(args,(str,list,tuple)):
# if len(args) > 5:
# print('传入的对象长度大于5')
# else:
# print('传入的对象长度小于5')
# else:
# print('类型有误')
#
# getLen2(['a','b','d','r','h','h']) '''
写入不定个数的字符串 拼接第一个和最后一个字符串
''' # def getStr(*args):
# return args[0] + args[-1]
#
# print(getStr('1','2','3')) '''
传入多个参数 以list返回
'''
# def getList(*args):
# list = []
# for i in args:
# list.append(i)
# return list
#
# list01 = getList(1,2,3,4)
# print(list01) '''
定义一个函数 输入不定个数的数字,返回所有数字的和
'''
# def getSum(*args):
# x = 0
# for i in args:
# x += i
# return x
#
# sum = (getSum(1,2,3,4))
# print(sum)

  

'''
模拟ATM机 1、登录验证
2、金额验证
3、交易完成
''' '''
#登录验证功能
def login(passwd):
pwd = '888888'
if passwd == pwd:
return True
else:
return False # 2、金额验证
def checkMoney(money):
if money.isdigit():
if int(money) % 100 ==0 and 0 <= int(money) <= 1000:
return money
else:
return False
else:
return False #业务逻辑写在主程序
def main():
# 1、登录验证
for i in range(3):
passwd = input('请输入您的密码:')
if passwd == 'n':
break
if login(passwd):
# 2、金额验证
while True:
money = input('请输入金额:')
money = checkMoney(money)
if money:
print('成功取出%s元'%money)
break
else:
print('输入的金额有误,请输入正确的金额')
# 3、交易完成
print('交易完成') else:
if i == 2:
print('您连续三次输入的密码有误,账号已经冻结')
break
print('密码有误') main()
''' '''
分数积
''' def EvenSum(n):
x = 0
for i in range(2,n+2,2):
x += 1 / i
return x def OddSum(n):
x = 0
for i in range(1,n+1,2):
x += 1 / i
return x def main():
#接受一个数字
num = int(input('请输入一个数字:'))
#判断奇数还是偶数
if num % 2 == 0:
k = EvenSum(num)
print('偶数的分数积是:%f'%k)
else:
k = OddSum(num)
print('奇数的分数积是:%f'%k) main()