Python函数

1.函数的定义

使用def关键字和缩进语法来定义一个函数:

def funcname(args):
    <code statement>

2.函数的参数

 

参数类型描述
位置参数
(必须参数)
如果不输入参数名称,则必须按照指定顺序输入参数;若输出参数名称,则可以不按照指定顺序输入参数
默认参数在设置参数时已设定默认值,故输入参数时可忽略,但若要重新配置该参数值,则按照位置参数规则执行
可变参数使用*,则连续输入多个的个体参数,会被自动封装为tuple,但输入类容器结构数据时,在前类容器前加*进行拆包
关键字参数使用**,可以输入任意的key=value键值对形式的参数,会自动封装为dict,但若输入dict为参数,则需要在dict加**进行拆包

 

def func(name,age,weight=65):
    print('%s is %s years old and his weight is %s kiligrams'%(name,age,weight))
func('grant',18)
func('lisa',20,50)
func(age=30,name='peter')
func(weight=100,age=60,name='wood')
#以上都能正常输出
def func2(*L):#定义一个可变长的函数
    for i in L:
        print(i)
func2(1,2,3)
List=[4,5,6]
func2(*List)#在列表前加*拆包
#以上都能正常输出
def func3(**kw):#定义一个关键字式函数
    print(kw)
func3(name='grant',age=18)
func3(**{'name':'grant','age':18})#在字典前加**拆包
#以上都能正常输出

3. 作用域

Python中,变量的作用域一共分四种:

 

  • 局部-Local
  • 闭包函数的外层函数-Enclosing
  • 全局-Global
  • 内建-Built-in

Python解释器按照L-E-G-B的原则进行变量查找

 

变量类型描述
不可变:int,str,tuple内层函数仅对变量有查看权,无修改权,除非使用global,nonlocal 进行作用域声明
可变:list,set,dict内层函数可以对变量进行查看和修改

4.匿名函数

使用lambda关键字来创建匿名函数

匿名函数只能是一行的表达式,所以一般只能封装比较简单的逻辑,但好处是因为没有函数名不用担心名称冲突,而且执行完毕既释放内存空间.

lambda x:x**2

5.递归函数

一个函数在内部调用其自身被称为递归函数,所有的递归函数都可以改写为循环.

由于函数调用都是通过栈的方式实现的,而栈的大小是有限的,所有当递归次数过多时,会导致栈溢出,从而抛出错误

RuntimeError: maximum recursion depth exceeded in comparison

使用递归函数的原则:

 

  • 每一次的递归都能使问题规模减小
  • 必须设置递归的退出条件
def recursion(n):
    n=n-2
    print(n)
    if n<1:
        print('end')
    else:
        return recursion(n) 

recursion(10)

输出结果:

8
6
4
2
0
end

6.yield和return

 

  • return

函数使用return作为结果输出,若不指定输出结果,则默认返回None,同时return None也可以简写为return

函数一旦执行return语句,则整个函数执行结束

在不指定格式的前提下,若用return同时返回多个结果,则会默认把结果封装成一个tuple

def func(x,y,z):
    return x,y,z
print(func(1,2,3))
>>>(1,2,3)

 

  • yield     生成器

函数中一旦出现yield,则该函数不在是函数,而是生成器(generator).

def func(num):
    for i in range(num):
        yield i
t=func(5)#此时t为生成器对象
print(type(t))
#输出结果:
>>><class 'generator'>
>>>

生成器是惰性的,可以用list/tuple/set直接接收生成器函数的全部输出结果,也可以用for循环对生成器函数进行遍历.

t1=func(5)
print(list(t1))
t2=func(4)
print(set(t2))
t3=func(3)
print(tuple(t3))
t4=func(2)
for i in t4:
    print (i,end='//')
------------------------------------
#输出结果:
------------------------------------
[0, 1, 2, 3, 4]
{0, 1, 2, 3}
(0, 1, 2)
0//1//

 

生成器需要被一个变量对象接收,如果每次重新去调用生成器函数,每次都会是生成器函数初始化的结果.

def func(num):
    for i in range(num):
        yield i

print(next(func(3)))
print(next(func(3)))
print(next(func(3)))
--------------------------------------
#输出结果:
>>>0
>>>0
>>>0

生成器好比单行道,只能向前不能后退,直到抛出StopIteration的异常.

t1=func(3)
print(next(t1),end='/')
print(next(t1),end='/')
print(next(t1))
print(next(t1))
---------------------------------------
#输出结果:
0/1/2
Traceback (most recent call last):
  File "D:/Pycharm/TEST/0410.py", line 14, in <module>
    print(next(t1))
StopIteration

yield 实现协程

def consumer():
    r1 = '111'
    r2 = '222'
    while True:
        n1 = yield r1
        print('n1:',n1)
        if n1:
            print('None')
        print('[CONSUMER] Consuming %s...' % n1)
        n2 = yield r2
        print('n2:',n2)
        r = '200 OK'

def produce(c):
    k=c.send(None)
    print('k:',k)
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        t = c.send(n)
        print('t:',t)
        print('[PRODUCER] Consumer return: %s' % t)
    c.close()

c = consumer()
produce(c)
-------------------------------------------------------------------------------
#执行结果:
k: 111
[PRODUCER] Producing 1...
n1: 1
None
[CONSUMER] Consuming 1...
t: 222
[PRODUCER] Consumer return: 222
[PRODUCER] Producing 2...
n2: 2
t: 111
[PRODUCER] Consumer return: 111
[PRODUCER] Producing 3...
n1: 3
None
[CONSUMER] Consuming 3...
t: 222
[PRODUCER] Consumer return: 222
[PRODUCER] Producing 4...
n2: 4
t: 111
[PRODUCER] Consumer return: 111
[PRODUCER] Producing 5...
n1: 5
None
[CONSUMER] Consuming 5...
t: 222
[PRODUCER] Consumer return: 222

以上为典型的生产者消费者模型

在该模型中, yield的原则为左接收(先),右发生(后),而send是先发送,后接收

第一步,使用send(None)命令激活(只能使用该固定格式),和该命令对应的yield执行右发生

当第二次及以后的send时,yield执行左接收后,执行其他代码,直到遇到下一个yield执行右发送,从而完成一次循环

当yield完成一次循环后,send接收yield的发送值并执行其他代码,直到下一次send

最后,使用close()命令,关闭整个流程

 

yield和return的位置关系

若yield之后还存在return关键词,则return之后携带的内容只会出现在生成器函数抛出异常时的StopIteration中:

def func():
    yield 1
    yield 2
    return 'end'

t=func()
print(next(t))
print(next(t))
print(next(t))
---------------------------------------
#输出结果:
1
2
Traceback (most recent call last):
  File "D:/Pycharm/TEST/0410.py", line 11, in <module>
    print(next(t))
StopIteration: end

7.闭包函数

闭包函数本质上就是函数内部再嵌套函数,并且内层函数需要调用外出函数的变量,最后内层函数作为结果输出.

闭包函数输出的是一个函数,所以要拿到最终的结果,需要对输出的函数再次进行调用.

闭包函数的使用最需要注意以下两点:

 

  • 内外层函数变量的作用域问题,切记内层函数对外出函数的变量只有查看权,无修改权
  • 由于闭包函数输出的是一个还未被执行的函数,只在在该函数最终执行时才会去查找调用相关变量,所以这个过程中的变量需要时稳定的,若为不稳定的变量则会影响输出结果.
def out():
    count=0#此为不可变类型,故内层函数要修改的话需要声明,用[0]代替则不需要声明
    def inner():
        nonlocal count
        count+=1
        return count
    return inner

t=out()
print(t(),t(),t())
---------------------------------------
#输出结果:
>>>1 2 3
def out(n):
    f=[]
    for i in range(1,n):
        def inner():
            return i*i
        f.append(inner)
    return f

f1,f2,f3=out(4)

print(f1(),f2(),f3())
---------------------------------------
#输出结果:
>>>9 9 9 #由于闭包返回的函数在没有在调用时并没有执行,所以在最后执行再去查找变量时,变量i已经是3,所以输出结果都是9,并不是1,4,9!
def out(n):
    f=[]
    for i in range(1,n):
        def inner(x=i):
            return x*x
        f.append(inner)
    return f

f1,f2,f3=out(4)

print(f1(),f2(),f3())
---------------------------------------
#输出结果:
>>>1 4 9 #由于在内层函数每次都用参数x绑定了变量i,所以最终输出结果为1,4,9

8.装饰器

装饰器类似于闭包,本质上都是用函数是'包装'函数.

def dec(func):
    def wrapper(*args,**kwargs):
        print('This is a decorator')
        func(*args,**kwargs)
    return wrapper

def func1():
    print('run func1')
func1()
print('=======================================')
#用函数dec修饰func1后
func1=dec(func1)
func1()
---------------------------------------
#输出结果:
run func1
=======================================
This is a decorator
run func1

为了简洁性和代码的复用性,Python可以采用@语法糖的形式,@dec的语法是等同于func2=dec(func2)

@dec
def func2():
    print('func2 is running')
func2()
-----------------------------------------
#输出结果:
This is a decorator
func2 is running

从形式上来说,确实达到了在不改动原代码的前提下,为原函数增加的新的功能,但其实原函数的元信息已经改变

def func2():
    print('func2 is running')
print(func2.__name__)

@dec
def func2():
    print('func2 is running')
print(func2.__name__)
---------------------------------------
#输出结果:
func2
wrapper

但Python 用functools模块中的wraps方法解决了这个问题,这才是真正的装饰器

import functools

def dec(func):
    @functools.wraps(func)
    def wrapper(*args,**kwargs):
        print('This is a decorator')
        func(*args,**kwargs)
    return wrapper
def func2():
    print('func2 is running')
print(func2.__name__)

@dec
def func2():
    print('func2 is running')
print(func2.__name__)
---------------------------------------
#输出结果:
func2
func2

以上是不带参数的装饰器,若需要增加参数的话,就得再增加一层包含的层级

import functools

def dec(text):
    print(text)
    def wrap(func):
        @functools.wraps(func)
        def wrapper(*args,**kwargs):
            print('decorator with parameter')
            return func(*args,**kwargs)
        return wrapper
    return wrap

@dec('parameter')
def func():
    print('func is running')
func()
---------------------------------------
#输出结果:
parameter
decorator with parameter
func is running

装饰器也是可以多层嵌套的:等同于a装饰(b装饰(c装饰func)),既 func=a(b(c(func)))

@a
@b
@c
def func():
    pass

在执行函数前打印start,执行函数后打印end的装饰器例子:

import functools
def dec(func):
    @functools.wraps(func)
    def wrapper(*args,**kwargs):
        print('start')
        func(*args,**kwargs)
        print('end')
    return wrapper
@dec
def func():
    print('func is running!')
func()
---------------------------------------
#输出结果:
start
func is running!
end

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值