文章目录
一、普通函数
用def语句是定义的函数是所有程序的基础。
函数特性
- 避免程序代码冗余
- 更易扩展方便修改
- 保持代码一致性
语法格式
def functionname( parameters ):
"函数_文档字符串"
function_suite
return [expression]
对语法格式的一些说明:
- 定义函数时参数不需要声明类型,由调用者传递的实参类型以及python解释器的推断来决定的。也不需要声明指定函数返回值类型。
- 函数返回值return作用:1. 给函数调用者返回一个对象,即调用函数可以用变量接收默认值为空。可以跟多个对象,系统会自动封装成一个元组返回2.结束函数。
- 我们可以明确的知道python函数的参数不需要指定类型,但有时候我们需要为参数附着一些信息,但又不能影响函数的使用:
def add(x:int,y:int) ->int:
return x+y
print(help(add))#add(x: int, y: int) -> int
如果我们要对函数进行说明的话,可以如语法格式一样编写在函数_文档字符串中,函数的注解说明保存在__annotations__属性中。
函数参数类型
函数参数可以分为普通参数、默认参数、不定长参数、关键参数等。一般顺序:普通形参、默认参数、不定长。
默认值参数
定义函数时,python支持使用默认值参数。此时可以不用为设置了默认值参数的形参进行传值。
格式
def functionname(… 形参=默认值)
实例
def spam(a,b=2):
print(a,b)
spam(1)#1 2
spam(1,b=3)#1 3
spam(1,3)#1 3
对于实例的一些说明:
- 当我们需要改变默认值参数时有以上两种方法改变默认参数。
- 需要值得注意的是默认值是可变容器的话应该这样编写:
def spam(a,n=None):
if n is None:
b=[]
原因:默认值参数只会在函数定义的时候绑定一次,可变容器无法初始化,即往里面添加的内容在调用新的函数时无法被清除。
x=12
def spam(a=x):
print(a)
spam()#12
x=22
spam()#12
关键字参数
主要指的是调用函数时的参数传递方式,与函数定义无关,形式上特点与默认值参数一样。
不定长参数
格式
*args、**kwargs是不定长参数的两种形式。args是一个元组、kwargs是一个自典。
def avg(first,*rest):
return first+sum(rest)
a=avg(1,2,4)#7
b=avg(1,*[1,2])#4
对于不定长参数一些说明:
- 调用是以上两种方法进行的。不能用avg(1,[1,2])调用,这就说明*参数必须在后面的原因当然这只是一般情况,下面将会演示特殊情况达成特殊的目的,不过值得注意的是**参数必须在最后面这是不变的。
编写只接收关键字参数的函数实例
def recv(maxsize,*,block):
pass
recv(1024,True)#TypeError: recv() takes 1 positional argument but 2 were given
recv(1024,block=True)
这样编写函数是可以提高代码的可读性。
二、匿名函数
匿名函数是用lambda表达式来声明的没有函数名字的临时使用的小函数,这种函数局限性很大。匿名函数往往用作回调函数,如给某些函数的key参数传值、callback参数等
格式
lambda 参数:返回结果语句
实例
add=lambda x,y:x+y
add(1,2)
names=[
'Divad',"Jhon","Alex"
]
a=sorted(names,key=lambda name:name)#
print(a)#['Alex', 'Divad', 'Jhon']
key=lambda name:name
print(key(names))# ['Divad', 'Jhon', 'Alex']
关于key参数使用lambda理解:由上面可以理解key参数是如何运行的。
在上面我们讨论了普通函数绑定变量是在在函数定义的时候,但匿名函数是在运行时直接绑定的。
对匿名函数的一些讨论
- 关于匿名函数的变量作用域问题,下面的代码中变量是在外部作用域定义的,对于lambda表达式而言不是局部变量。
x=[]
for i in range(10):
x.append(lambda i:i**2)
print(x[0]())#TypeError: <lambda>() missing 1 required positional argument: 'i'
#正确写法:x.append(lambda i=i:i**2)
递归函数
特点
- 调用自身函数【每调用一层递归时,问题规模都应比上一层减少】
- 有结束条件;递归能做的事情,循环都可以解决,递归效率在很多时候很低,不推荐使用。
- 递归函数必须要设置终点;通常都有入口出口
阶乘
def fact(n):
if n==1:
return 1
return n*fact(n-1)
print(fact(2))
例子演示:斐波那契数列
def Fibonacci_sequence_function(n):
if n==1:return 0
if n==2:return 1
return Fibonacci_sequence_function(n-1)+Fibonacci_sequence_function(n-2)
闭包
内部函数使用外部函数的局部变量,那么我们就称内部函数为闭包。
#闭包函数,其中 exponent 称为自由变量
def nth_power(exponent):
def exponent_of(base):
return base ** exponent
return exponent_of # 返回值是 exponent_of 函数
square = nth_power(2) # 计算一个数的平方
cube = nth_power(3) # 计算一个数的立方
print(square(2)) # 计算 2 的平方
print(cube(2)) # 计算 2 的立方
条件:
- 外部函数中定义了内部函数
- 外部函数有返回值且为内部函数名。
- 内部函数引用了外部函数变量。
格式
def 外部函数():
.....
def 内部函数():
......1
return 内部函数
无论何时,当在编写代码时,遇到需要将附加额外的状态或者保存额外状态给函数时,可以使用闭包函数。下面的例题需要将template的值保存,并在后面的方法中使用。
from urllib.request import urlopen
class UrlTemplate():
def __init__(self,template):
self.template=template
def open(self,**kwargs):
return urlopen(self.template.format_map(kwargs))
yahoo=UrlTemplate('http://laowang.com?s={names}$f={fields}')
for line in yahoo.open(name='IBM',fields='sllelv'):
print(line.decode("utf-8"))
def urlTemplate(template):
def opener(**kwargs):
return urlopen(template.format_map(kwargs))
return opener
yahoo1=urlTemplate('http://laowang.com?s={names}$f={fields}')
for line in yahoo(name='IBM',fields='sllelv'):
print(line.decode("utf-8"))
三、回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
基于回调函数的软件设计常常会面临使代码陷入一团糟,部分原因是因为代码从发起初始请求到开始回调执行的过程中,回调函数与这个环境是脱离的。因此让回调函数在涉及多个步骤的任务处理中能继续执行,就必须携带一些信息状态。可以使用类、闭包。
#----
def apply_async(func,args,*,callback):
'''定义一个回调函数'''
result=func(*args)
callback(result)
def add(x,y):
return x+y
#----没有携带信息
def print_result(result):
print(result)
apply_async(add,(1,2),callback=print_result)#3
apply_async(add,('hi','hello'),callback=print_result)#hihello
#----类
class ResultHandler():
def __init__(self):
self.sequence=0
def handler(self,result):
self.sequence+=1
print('[{}],{}'.format(self.sequence,result))
r=ResultHandler()
apply_async(add,(1,2),callback=r.handler)#[1],3
apply_async(add,('hi','hello'),callback=r.handler)#h[2],hihello
#-----闭包
def make_handler():
sequence=0
def handler(result):
nonlocal sequence
sequence+=1
print('[{}],{}'.format(sequence, result))
return handler
handler=make_handler()
apply_async(add,(1,2),callback=handler)#[1],3
apply_async(add,('hi','hello'),callback=handler)#h[2],hihello
参考书籍:python食谱、Python 函数 | 菜鸟教程 (runoob.com)、python程序设计等