Python进阶语法之函数和高阶函数

本文详细探讨了Python的函数特性,包括函数的定义、参数类型、全局与局部变量,以及匿名表达式。此外,还介绍了递归调用的概念,并通过实例展示了递归在解决斐波那契数列问题上的应用。最后,文章深入讲解了高阶函数,如max、min、sorted、reduce和map,并引入了装饰器的概念及其在代码增强和功能扩展上的作用。
摘要由CSDN通过智能技术生成

文章目录

函数

一、函数的性质:

1、函数的定义
  • 函数是组织好的、可重复使用的、用来实现单一或者相关联功能的代码段,就是将面向过程的代码变的"模块化",能够实现重复调用。
2、函数的自定义用法
2.1、使用 def 关键字定义函数,def后面跟 函数名称 (本质:变量)、圆括号**()和冒号:**
  • a) 下面示例一个打印问候语的简单函数,名为greet_user():
 def greet_user():
 	'''显示简单的问候语'''
 	print('Hello!')

 greet_user()
2.2、圆括号中用于定义函数内部需要使用的参数–> 被叫做形参。
  • b)修改一下上边这个函数,往圆括号中传入’姓名’实参。
 def  greet_user(username):
 	'''显示简单的问候语'''
 	print("Hello,"+ username.title() + "!")
 
 greet_user('zhangqin')
2.3、函数内部代码块通常第一行会写多行注释,作为解释函数作用的注释,在上面简单的函数代码中我们可以看出,在函数开始前写注释有利于开发人员对函数一串代码的功能有一个明确的认识。
2.4、代码块结束以后使用“return”将函数内部产生的“结果”—返回到-----函数外部,结束函数的执行,也可以认为是替代了print函数的作用;
  • 注意:
    • a) 如果不使用return、函数结果为None
    • b) 注意代码缩进
通常在代码的结束处
return 表达式
2.5、函数定义完,使用函数时叫做—调用函数—,如何调用?函数名后面跟圆括号()。
2.6、调用函数时需要在–圆括号—中----“写入实参”-----传递给函数模块里的----“形参”—
2.7、函数执行的顺序是:从调用函数开始执行,函数定义时,程序不参与执行。举例说明函数是怎样工作的:
# 自定义函数计算1~N的和
def total(start, end):
 ""计算某个范围的和""
 sum = 0
 for i in range(start, end + 1):
 	sum += i
 return sum

# 将实参传给形参。格式:函数().py
print(total(1,100))
print(total(1,1000))

2.8、函数的作用
  • a)函数可以用来降低代码的冗余度,也可以给代码阅读者更清晰的思想(一个函数代表一个功能)。

二、函数的参数:

1、默认值参数
  • a) Python中定义带有默认值参数的函数,其语法格式如下:

    def 函数名(…,形参名,形参名=默认值):

    代码块

  • b)注意:在使用此格式定义函数时,指定有默认值的形式参数必须在所有没默认值参数的最后,否则会产生语法错误。

  • c) 下面程序演示了如何定义和调用有默认值参数的函数

#str1没有默认值参数,str2有默认值参数
def dis_str(str1,str2 ="www.python.com"):
 	print("str1:",str1)
 	print("str2:",str2)
 
dis_str("www.shell.com")
dis_str("www.java.com","www.golang.com")

运行结果为:

str1: www.shell.com

str2: www.python.com

str1: www.java.com

str1: www.golang.com


传入一个参数,默认会传给str1,str2会使用默认的参数。
调用dis_str函数时,优先会使用传递的实参。

2、位置参数
  • a)形参和实参之间的顺序需要一一对应,顺序不能变化。
  • b)函数中的形参如何定义,那么调用时就必须以对应的顺序去传参。
def rangeSum(start, end):
		'''求指定范围中所有数字的和'''
		sum = 0
		for i in range(start, end + 1):
			sum += 1
		return sum

rangeSum(1, 10)
  • c) if _name _ == 'main’方法
    缩进下的代码能够让此函数模块被另一个函数调用时结果不执行,本函数运算过程正常运行。
def numSum(start,end):
	total = 0
	for i in range(start, end + 1):
		total += i
   return f'({start}, {end + 1})中整数的和为{total}'

if _name_ == '_main_':
	print(numSum(1, 50))
3、关键字参数
  • 形参和实参之间的对应关系
  • 关键字参数传参形式: 形参名 = 数据
  • 调用函数时:rangeSum(形参1 = 值1,形参2 = 值2)
print(rangeSum(start=100, end=1000))
print(rangeSum(end=1000,start=100))
4、位置参数和关键字参数混用
  • a) 位置参数必须在前面,关键字参数在后面。
  • b) 位置参数必须按照形参顺序传参。
def numSum(x, y, z):
	print(f'x:{x}, y:{y}, z:{z}')
	return x + y + z
	
print(numSum(10, 20, z=30))
print(numSum(10, z=50, y=20))

# positional argument follows keyword argument(错误)
# print(numSum(z=20, y=10, 1)) 
5、不定长参数(带*的变量)
  • 1、不定长参数包含:*args, **kwargs

  • 2、一个的不定长参数必须放在两个的不定长参数前面

  • 3、一个*的不定长参数只能接收"位置参数":两个**的不定长参数只能接收关键字参数。

  • 4、不定长参数可以一次性传入N个参数(N>=0),可以解决实参和形参数量不一致的问题。

  • 5、两个不定长参数的区别:

    • *args 接收"位置参数’'后将所有的数据转换为一个元组()

    • kwargs 接收’‘关键字参数’'后将所有数据转换为一个字典{**key:values}

  • 6、不定长参数代码解释:

 	def selfTest(*args, **kwargs):
		pass
		print(args)
		print(kwargs)
	
 	selfTest(1, 2, 3, 4, x=1, y=2, z=3)

运行结果为:

(1,2,3)

{‘x’:1,‘y’:2,‘z’:3}


6、参数指定的数据类型
  • a) 给形参赋予默认值,默认值是什么数据类型等于"传参"的数据类型。

  • b) 直接以"冒号数据类型(形参:int)"的形式创建形参。

  • c) 在定义函数时使用"-> int" 表明此函数返回什么数据类型。

  • d) 参数指定的数据类型代码演示:

def rangeSum(start=1, end=100) -> int:
	sum = 0
	for i in range(start, end + 1):
		sum += i
    return sum
    
rangeSum()

print('*****也可以直接说明要传给为形参的数据类型*****')
# 声明指定函数要返回的数据类型。
def rangeSum(start: int, end: int):
	sum = 0
	for i in range(start, end + 1):
		sum += i
    return sum
    
rangeSum(100)

三、函数中的全局变量和局部变量:

1、全局变量
  • a) 在函数外部定义的变量,或者在函数的内部,用global关键字定义的变量,就是全局变量
  • b) 下面是一段全局变量的代码:
b = 10              # (1) 定义一个全局变量
print(b)
def func():
    b = 30
	return b		# 获取全局变量b的值
func()
print(b)
# 10  10 
2、局部变量
  • a)、定义在函数和类里的变量叫做局部变量,局部变量的作用域为从定义开始到函数和类结束。

  • b)、下面是一段局部变量的代码:

def func():
	a = 1                          # 1.定义一个局部变量
	print(a)                       # 2.获取局部变量
	a = 20                         # 3.修改局部变量
	print(a)                       # 4.获取局部变量
func()
# 函数外部无法调用
print(a)
# 1  20   name 'a' is not defined 外部调用显示a没有被定义。
  • c)、局部变量的作用或意义:
    • 1、局部变量创建于函数或类中,当函数或者是类被调用时局部变量才开始创建
    • 2、当函数或类结束时,局部变量被销毁。
3、在函数内部定义或者修改全局变量
  • 可以使用global和nonlocal保留字在函数内部使用全局变量

  • 下面是相关操作python代码文档:

c = 100
def func():
    print(c) 					# 100
	c = 200
   # print(c)
func()
print(c)                         # 100

# global关键字:在函数内部修改全局变量
"""
global 变量
变量 = 值
"""

c = 100
def func1():	
	global c                     # 标记声明这个c变量为全局
	c = 200                      # 修改全局变量
func1()
print(c)                         # 200

# nonlocal:在函数A的函数B中修改函数A的变量
'''
nonlocal  变量
变量 = 值
'''
def A():
	z = 0
	def B():
		nonlocal z
		z = 6
    B()
    print(z)
    
A()

四、匿名表达式

1、匿名表达式的定义
  • a)为函数的简化,表达式名称为lambda,它和一般函数的关系可以理解为单分支结构和三目运算符的关系。

    def numSum(num1, num2):
    	'''计算两个数字的和'''
    	return num1 + num2
    	
    numSum(10, 20)
    

    转换为匿名函数:

    def numSum(num1, num2)	
        new_NumSum = lambda num1, num2: num1 + num2
    	return new_NumSum
    
    newSum(10, 20)
    
  • b)它的语法为:

    ​ 1. 创建匿名函数 函数名 = lambda 形参:返回值

    ​ 2. 调用匿名函数 函数名(实参)

五、递归调用

1、递归调用的概念
  • a)函数中的一种,函数调用函数的一种方式。

  • b)在程序设计领域,递归是指函数(或方法)直接或间接调用自身的一种操作。

  • c)递归不能出现无终止的调用,它的出口可用if语句来设置,在满足某种条件时不再继续,调用某个值,结束递归。

  • d)递归的过程每一步用的都是同一个算法,计算机只需要自顶向下不断重复即可。

2、分别用递推和递归的方法计算同一个函数
  • a、用正向递推的方式计算阶乘
def iterative_fact(n):
	fact = 1
	for i in range(1, n + 1):
    	fact *= i
	return fact

iterative_fact(5)
  • b、用逆向递归的方式计算阶乘

def recursive_fact(n):
	if n <= 1:
    	return n
	else:
    	return n * recursive_fact(n - 1)

recursive_fact(5)
# 函数使用递推思维和递归思维最大的不同点就是:
# 递归思维体现在函数自己调用自己。
3、递归思想优缺点

​ 1)能使用循环解决的就能使用递归思维。

​ 2)递归方式需要函数做大量的压栈和弹栈操作,所以程序的运行速度比不用递归实现要慢。

​ 3) 递归使用时需要谨慎,如果涉及计算量很大,有一个拓栈和压栈的过程,拓栈是容易内存溢出。

4、递归思想解决斐波那契数列问题

​ 练习:求斐波那契数列中第n个数的值:1、1、2、3、8、13、21、34…(这里的n可以是任意正整数,可以通过输入来确定)

def fib(N):
    if N == 1 or N == 2:
        return 1
    else:
        return fib(N - 1) + fib(N - 2)

print(fib(9))
"""
fib(9) = fib(8) + fib(7)
fib(8) = fib(7) + fib(6)
fib(7) = fib(6) + fib(5)
fib(6) = fib(5) + fib(4)
fib(5) = fib(4) + fib(3)
fib(4) = fib(3) + fib(2)
fib(3) = fib(2) + fib(1)
"""

六、高阶函数

1、高阶函数的概念
  • a) 就是一个函数可以用来接收另一个函数作为参数,这样的函数叫做高阶函数。

  • b) 自定义函数就相当于定义了一个类型是function的变量。

    (将一个函数的的值传递给另一个函数)示例如下:

    def bar():
    	return 'in the bar ...'
    
    print(bar())
    # 结果为:'in the bar ...'
    
    a = bar()
    print(a())
    # 结果也为:'in the bar ...'
    
  • c) 一个函数也可以被当做是另一个函数的返回值。

    (一个函数作为另一个函数的返回值)示例如下:

 def func1():
 	print('这是一个函数')
 	
 def func2(func):
 	print('这是另一个函数')
 	func()
 	
 func2(func1)
 # 结果为:
 这是另一个函数
 这是一个函数
2、python中常见的高阶函数
  • max、min、sorted、map、reduce等。
2.1、max、min函数
  • a) 一般我们使用max和min函数获取容器中的最大元素和最小元素。

    • 在一般函数里,我们这样使用max、min函数:
      • max(函数)
nums = [10,5,30,100,900,666]
print(max(nums))
# 结果为:900
  • b) 高阶函数里的要求及用法:

      1. max(容器,key = 函数)
      1. key来决定使用怎样的方式决定容器中参数的最大值。
      1. 此函数有且只有一个形参,且必须要有返回值。
nums = [10, 55, 67, 666, 900]

def unitNum(num):
	return num % 10
	
print(max(nums,key = unitNum))
print(max(nums,key = lambda num: num % 10))
print(min(nums,key = unitNum))
# 结果为:
    67
    67
    10
2.2、sorted函数
  • a)一般使用sorted指定的形式对容器中的元素排序,默认升序。

  • b)sorted函数的用法:
    sorted(容器,key=函数)

    nums = [10, 55, 67, 666, 900]
    print(sorted(nums, key=lambda num: num % 10))
    # 结果是:
    	[10, 900, 55, 666, 67]
    
2.3、reduce函数
  • a)一般使用reduce函数对容器中的每个元素做累计(累加、累乘等)。

  • b)reduce函数的使用要求:

    1. 语法:reduce(函数,容器,初始值)

    2. 函数有两个形参,第一个形参开始指向初始值,然后再指向每次累计的结果。

    3. 必须要有返回值return

# 定义一个函数,对其中元素做累乘
from functools import reduce
      
nums = [10, 55, 67, 666, 900]
def a(total, num):
	'''对列表中元素做累乘'''
	return total * num
      
print(reduce(a, nums, 1))
print(reduce(lambda total,num: total * num, nums, 1))
# 结果是:
	 22087890000
	 22087890000


# 定义一个函数,对其中元素做累加
nums1 = [10, 5, 30, 100, 900, 666]
def plus(num1,i)'''对列表中元素做累加'''
    return num1 + i
	
result = reduce(lambda num1, i: num1 + i, nums1, 1)
print(result)
# 结果是:1712   
	

c) reduce和for循环的区别:

​ reduce性能不及for循环,但是如果从代码可读性来说,可以用reduce。

2.4、map函数
  • a) 语法: map(函数,容器1,容器2,…)

    将N个容器按照函数中指定的方式进行转换,返回一个map对象(map对象是一个可迭代对象,可以使用构造器语法转换为列表等容器)。

  • b) 函数有N(容器数量)个形参。每个形参指向每个容器中的每一个元素。

  • c) 函数必须有返回值,返回值构成map对象的每一个元素

"""将列表[10, 5, 30, 100, 900, 666]中的每个元素乘以2"""
nums = [10, 5, 30, 100, 900, 666]

result = map(lambda num: num * 2, nums)
print(result)
print(list(result))
print(tuple(result))

# <map object 映射对象 at 0x00000188AA9D98B0>
# [20, 10, 60, 200, 1800, 1332]
# ()
3、装饰器
3.1、装饰器的定义
  • 装饰器是用来装饰函数的,能够在不修改原函数(代码及结构)的情况下额外给函数增加新的功能
3.2、高阶函数三大功能回顾
  • a)函数中传递函数

    • 下面的代码中,func1是一个普通的函数,返回a + b的和。func2中多定义了一个func函数,在运行时,函数先执行func1,再把func1作为参数传入func2执行func2。
def func1(a,b):
	print(f'函数【{func1}】正在执行')
	return a + b
	
def func2(func, c, d):
	print(f'函数【{func2}】正在执行')
	return func(c, d)
	
	
# func1(1, 2)
# 函数【func1】正在执行
# 3
func2(func1, 3, 4)
# 函数【func2】正在执行
# 函数【func1】正在执行
# 7
  • b)函数中定义函数

    • 在定义一个函数后,可以继续在函数内部定义新的函数。
def func1():
	print(f'函数【func1】正在执行')
	
	def func2():
		print(f'内部函数【func2】正在执行')
    return func2()

func1()
# 函数【func1】正在执行
# 内部函数【func2】正在执行
func2()
#NameError: name 'func2' is not defined  未定义名称func2
  • c)函数作为函数的返回值

    • 接下来定义一个外部函数func1,再定义一个内部函数func2,最终func1将func2作为返回值返回。
def A(a, b):
	print(f'函数【A】正在执行')
	
	def B(c):
		print(f'函数【B】正在执行')
		return  a + b + c
    
    return B
    
B = A(10, 20)
print(B)
print(B(30))

#【函数A】正在执行
# <function A.<locals>.B at 0x000002DCEFC7B3A0>
#【函数B】正在执行
60
3.3、第一个装饰器
  • 在下边的代码中,首先定义了一个函数first_decorator,该函数接收函数为参数,之后在内部定义了一个名为name_wrapper的内部函数,最后返回以name_wrapper作为返回值。
def first_decorator(func):
	'''在执行被接收函数前后分别打印一段话'''
	def name_wrapper():
		print(f'被装饰的函数【func】即将执行')
		f = func()
		print(f'被装饰的函数【func】执行完毕')
        return f
    # 第二个函数不执行,返回内部整体内容
    return name_wrapper
    
def add():
	'测试效果'
	print('函数add正在执行')

# 调用第一个函数,把add函数实参传递给func形参。
add = first_decorator(add)
print(add())

# 被装饰的函数【func】即将执行
# 被装饰的函数【func】执行完毕
# 函数add正在执行

使用语法糖@ + 函数名,可以不需要先将add传递。直接就对函数实现装饰器的功能。

def first_decorator(func):
	'''在执行被接收函数前后分别打印一段话'''
	def name_wrapper():
		print(f'被装饰的函数【func】即将执行')
		f = func()
		print(f'被装饰的函数【func】执行完毕')
        return f
    # 第二个函数不执行,返回内部整体内容
    return name_wrapper
    
@first_decorator
def add():
	print('函数add正在执行')  
    
add()
# 被装饰的函数【func】即将执行
# 函数add正在执行
# 被装饰的函数【func】执行完毕
3.4、装饰器传参
  • 现在来试着对装饰器进行修改,往里面加入参数。
def first_decorator(func):
	'''在执行被接收函数前后分别打印一段话'''
	def name_wrapper(*args, **kwargs):
		print(f'被装饰的函数【func】即将执行')
		f = func(*args, **kwargs)
		print(f'被装饰的函数【func】执行完毕')
        return f
    # 第二个函数不执行,返回内部整体内容
    return name_wrapper
    
@first_decorator
def add(x, y):
	print('函数add正在执行')
    print(f'{x} + {y} 的结果为{x+y}')
    
add(1, 2)
# 结果为:
# 被装饰的函数【func】即将执行
# 函数add正在执行
# 1 + 2 的结果为3
# 被装饰的函数【func】执行完毕
3.5、装饰器的作用
  • a)装饰器是一种高级Python语法,可以对一个函数、方法或者类进行加工。相比于其它对函数和类进行加工的方式,装饰器语法简单,代码可读性高,在python项目中有广泛的应用,常被用于场景:

    • 插入日志、性能测试、事务处理、Web权限校验、Cache等。

    • 下面是一种比较经典的Web权限验证装饰器函数:

# 可以在函数体执行功能时在多做验证(Web权限验证)
def limit(kind):
	def inner(func):
		def outer(*args, **kwargs):
			result = func(*args, **kwargs)
			if result == '登陆成功'if kind == '会员'return result, '尊敬的vvvvvvip用户'
                else:
                	return result,'感谢白嫖用户登录'
            else:
            	return result
        return outer
     return inner
     
# 语法糖的'参数'是登录账号时程序同时验证账号权限得到的结果
@limit('非会员')                         # 输出结果看这里
def userLogin(username, pwd):
	if username == 'admin' and pwd == '123456':
		return '登陆成功'
	else:
		return '登陆失败'
print(userLogin('admin','123456'))      # 结果看这里

单,代码可读性高,在python项目中有广泛的应用,常被用于场景:

  + 插入日志、**性能测试、事务处理、Web权限校验**、Cache等。

  + 下面是一种比较经典的Web权限验证装饰器函数:
# 可以在函数体执行功能时在多做验证(Web权限验证)
def limit(kind):
	def inner(func):
		def outer(*args, **kwargs):
			result = func(*args, **kwargs)
			if result == '登陆成功'if kind == '会员'return result, '尊敬的vvvvvvip用户'
                else:
                	return result,'感谢白嫖用户登录'
            else:
            	return result
        return outer
     return inner
     
# 语法糖的'参数'是登录账号时程序同时验证账号权限得到的结果
@limit('非会员')                         # 输出结果看这里
def userLogin(username, pwd):
	if username == 'admin' and pwd == '123456':
		return '登陆成功'
	else:
		return '登陆失败'
print(userLogin('admin','123456'))      # 结果看这里
  • b)装饰器的优点是能够抽离出大量函数中与函数功能本身无关的雷同代码并继续复用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stiinput

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值