python函数


一、普通函数

用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程序设计等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值