python笔记(4)---函数(2)

函数使用(2)

Recall

复习一下
[注:]在python中的函数可以当作变量来进行赋值!!!
例子如下:

def fun(name):
    print("I am {}".format(name))
fun("zhenzhen")
f=fun#将函数fun赋值为f
f("xiongxiong")#然后进行调用也是可以进行执行的

回想一下上一次所提到的函数中的函数(也就是子函数),看下面这样的一个例子:

def fun(key):
    def subfun():
        if key=='1':
            print("I am {}".format(key+"号"))
        elif key=='0':
            print("I am {}".format(key+"号"))
    return subfun
f=fun("1")
f()

Question1:上面的写法是否正确,调用了f()之后会发生什么?

装饰器

python 的装饰器是相对于函数而言的,以下网上有一个不友好但是很恰当的比喻如下:
        每个人都有的内裤主要功能是用来遮羞,但是到了冬天它没法为我们防风御寒,咋办?我们想到的一个办法就是把内裤改造一下,让它变得更厚更长,这样一来,它不仅有遮羞功能,还能提供保暖,不过有个问题,这个内裤被我们改造成了长裤后,虽然还有遮羞功能,但本质上它不再是一条真正的内裤了。于是聪明的人们发明长裤,在不影响内裤的前提下,直接把长裤套在了内裤外面,这样内裤还是内裤,有了长裤后宝宝再也不冷了。装饰器就像我们这里说的长裤,在不影响内裤作用的前提下,给我们的身子提供了保暖的功效。


python的装饰器就是形如上面的功能,下面考虑这样的一个简单的场景:假定你现在要写100个函数:

def fun1():
    print("I am duanfeixiong !!!")
    pass
def fun2():
    print("I am duanfeixiong !!!")
    pass
def fun3():
    print("I am duanfeixiong !!!")
    pass
def fun4():
    print("I am duanfeixiong !!!")
    pass
def fun5():
    print("I am duanfeixiong !!!")
    pass
def fun6():
    print("I am duanfeixiong !!!")
    pass
......
def fun100():
    print("I am duanfeixiong !!!")
    pass

上面的100个函数每一个函数都要打印一句相同的字符串"I am duanfeixiong !!!",那么整段代码看起来显得极其的丑陋可读性差,那么对于这样的场景(实际场景往往更加复杂!),就可以使用python的装饰器的形式,我们写下这样的代码:
在老一点版本上可以这样写:

def summary(func):
    def wrapper():
        print("I am duanfeixiong!!!")
        return func()
    return wrapper
def fun():
    '''
    do something
    '''
    pass

#装饰部分
fun=summary(fun)
fun()

分析一下上面代码的执行过程:
首先我们定义了一个summary函数,传递进去的参数是一个函数fun, summary这个函数返回的是wrapper()函数,wrapper函数首先执行打印那句语句然后执行fun()部分,但是这样写法有点问题,如果fun函数有参数比如fun(key)怎么办,一个写法是这样的:

def summary(func):
    def wrapper(key):
        print("I am duanfeixiong!!!")
        return func(key)
    return wrapper
def fun(key):
    '''
    do something
    '''
    print(key)
    pass

#装饰部分
fun=summary(fun)
fun(key)

回忆一下上次提到的函数的子函数以及子函数作为参数进行返回,观察上面的方法不难看出,我们只需要把fun的参数移植到wrapper函数的参数那里就行,这样根据上面所说的就可以进行对被装饰的函数的参数传递

@语法糖

观察上面的函数可以了解到一个共同点都需要在装饰的时候使用一条赋值语句这样有点多余,并且作用域的使用不好把握,要是在整个代码中使用被装饰的函数的话,你不得不在你的代码的最上面使用那条赋值语句,这个时候来了一种新的方式,同样是上面的代码我们只需要如下的写法即可:

def summary(func):
    def wrapper():
        print("I am duanfeixiong!!!")
        return func()
    return wrapper

@summary #直接在函数声明的时候对其进行装饰,和赋值语句是等价的写法
def fun():
    '''
    do something
    '''
    pass

#装饰部分
#fun=summary(fun)可以删除这句话
fun()

生成器和生成函数

重新回到for循环的地方谈一谈基于内容的for循环,我们知道要是对一个list进行遍历,并且每一次拿到list中的值进行打印的话,那么采用下面的语句是再适合不过的:

L=[1,1,2,2,3,4,5,5]
for d in L:
    print(d)

那么可以被for循环直接作用的容易和数据类型有哪些?

  1. 集合类型的容器,例如 list,tuple,set,str,dict
  2. 生成器生成函数
    可以通过for循环直接访问的叫做可迭代对象

需要记住上面两种!!!

对于第一种类型而言我们已经很熟悉了,考虑一下第二种的使用:

生成器

创建方式如下:

L=[x**2 for x in range(100)] #这是一个列表解析式,对0-99的数字平方后放在L中

G=(x**2 for x in range(100)) #这是一个生成器不是tuple

阐述一下上面两种的本质上的区别:

L是一个集合类型的容器list,在初始化的时候已经决定了他的大小是100,而对于G而言并没有,G是一个生成器需要不断调用一个next函数不断返回下一个值,对于空间的开销极其低相比于list

>next(G)
0
>next(G)
1
>next(G)
4
....

也可以被for循环直接作用:

for d in G:
    print(d)

上面的for循环等价于对G不断的使用next()函数

生成函数

依旧是上面的例子和函数$x2$那么如果我们想写一个函数接受一个参数n返回从0到n-1的所有x2的值,那么我们可以这样写:

def fun(n):
    L=[]
    for i in range(n):
        L.append(i**2)
    return L

但是这样的写法太过于繁琐,list对空间的开销比较大,我们可以转而使用生成函数

def fun(n):
    for i in range(n):
        yield i**2
fun(10)#创建了一个生成器
print(type(fun(10)))#查看类型 自己打印一下!!!
next(fun(10))#next函数照样适用
#也可以
for d in fun(10):
    print(d)

yield关键字可以这样理解,在调用了next()函数之后,fun(10)中for循环前进一次,yield可以当作返回值,不同于别的普通函数的是:next()下一次的时候从上一次next()函数终止的位置继续往后执行!!!

posted @ 2020-11-23 19:41  差三岁  阅读(115)  评论(0编辑  收藏  举报