python_高级用法(闭包,装饰器,迭代器,生成器)

一、闭包

闭包概念:在一个内部函数中,对外部作用域的变量进行引用,(并且一般外部函数的返回值为内部函数),那么内部函数就被认为是闭包。

# test1:简单闭包
def outer(a):
    def inner(b):
        return a + b

    return inner


f = outer(1)
print("f.name is:", f.__name__)
print(f(2))
print(f(3))

f.name is: inner
3
4
# test2:闭包无法修改外部函数的局部变量
def outfunc():
    x = 0

    def infunc():
        x = 1
        print("infunc x is:", x)

    print("outfunc x is:", x)
    infunc()
    print("outfunc x is:", x)


outfunc()


outfunc x is: 0
infunc x is: 1
outfunc x is: 0
# test3:使用nolocal
def outfunc():
    x = 0

    def infunc():
        nonlocal x
        x = 1
        print("infunc x is:", x)

    print("outfunc x is:", x)
    infunc()
    print("outfunc x is:", x)


outfunc()


outfunc x is: 0
infunc x is: 1
outfunc x is: 1
# test 4:易错点
'''
按照大家正常的理解,应该输出的是0, 2, 4对吧?但实际输出的结果是:4, 4, 4. 原因是什么呢?
loop在python中是没有域的概念的,flist在像列表中添加func的时候,并没有保存i的值,
而是当执行f(2)的时候才去取,这时候循环已经结束,i的值是2,所以结果都是4。
'''

def outfunc():
    flist = []
    for i in range(4):
        def infunc(x):
            return i * x

        flist.append(infunc)
    return flist

flist = outfunc()
ret = [f(2) for f in flist]
print(ret)

def outfunc():
    flist = []
    for i in range(4):
        def makefunc(i):
            def infunc(x):
                return i * x

            return infunc

        flist.append(makefunc(i))
    return flist

flist = outfunc()
ret = [f(2) for f in flist]
print(ret)


[6, 6, 6, 6]
[0, 2, 4, 6]

二、装饰器

# 不带参数
def debug(func):
    def wrapper():
        print("[DEBUG]: befor {}()".format(func.__name__))
        func()
        print("[DEBUG]: after {}()".format(func.__name__))

    return wrapper

@debug
def hello():
    print("hello")

hello()

[DEBUG]: befor hello()
hello
[DEBUG]: after hello()
# 装饰函数带参数
def debug(func):
    def wrapper(*args, **kwargs):
        print("[DEBUG]: befor {}()".format(func.__name__))
        func(*args, **kwargs)
        print("[DEBUG]: after {}()".format(func.__name__))

    return wrapper


@debug
def hello(a, b, c):
    print("hello:", a, b, c)


hello("a", "b", "c")

[DEBUG]: befor hello()
hello: a b c
[DEBUG]: after hello()

def debug(level):
    def outwrapper(func):
        def wrapper(*args, **kwargs):
            print("[{}]: befor {}()".format(level, func.__name__))
            func(*args, **kwargs)
            print("[{}]: after {}()".format(level, func.__name__))

        return wrapper

    return outwrapper


@debug(level="INFO")
def hello(a, b, c):
    print("hello:", a, b, c)


hello("a", "b", "c")

[INFO]: befor hello()
hello: a b c
[INFO]: after hello()

三、迭代器

迭代是Python最强大的功能之一,是访问集合元素的一种方式。 迭代器是一个可以记住遍历的位置的对象。 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会退。 迭代器有两个基本的方法:iter() 和 next()。 字符串,列表或元组对象都可用于创建迭代器:

test1:

list_arr = [1, 2, 3, 4]
it = iter(list_arr)
print(type(list_arr), type(it))
print(next(it), next(it))

for i in it:
    print(i)

<class 'list'> <class 'list_iterator'>
1 2
3
4

test2:

把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__(); __iter__() 方法返回一个特殊的迭代器对象,; 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成;

class MyRange(object):
    def __init__(self, end):
        self.index = 0
        self.end = end

    def __iter__(self):
        return self

    def __next__(self):
        if self.index < self.end:
            x = self.index
            self.index += 1
            return x
        else:
            raise StopIteration


for i in MyRange(5):
    print(i)

my_range = MyRange(5)
print(next(my_range), next(my_range))

0
1
2
3
4
0 1

四、生成器

在 Python 中,使用了 yield 的函数被称为生成器(generator) 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。 调用一个生成器函数,返回的是一个迭代器对象。

test1:普通函数实现

def fab_list(max_n):
    n, a, b = 0, 0, 1
    ret = []
    while n < max_n:
        ret.append(b)
        a, b = b, a + b
        n += 1
    return ret


f = fab_list(6)
print(f)

[1, 1, 2, 3, 5, 8]

test2:yield实现

def fab_yield(max_n):
    n, a, b = 0, 0, 1
    while n < max_n:
        yield b
        a, b = b, a + b
        n += 1


f = fab_yield(6)
print(next(f), next(f), next(f), next(f), next(f), next(f))

1 1 2 3 5 8

解释:

yield的函数是一个生成器,而不是一个函数了,这个生成器有一个函数就是next函数, next就相当于“下一步”生成哪个数,这一次的next开始的地方是接着上一次的next停止的地方执行的, 所以调用next的时候,生成器并不会从foo函数的开始执行, 只是接着上一步停止的地方开始,然后遇到yield后,return出要生成的数,此步就结束。

五、参考与总结:

深入浅出python闭包 - 知乎

python中闭包详解 - 知乎

python 装饰器详解 - 知乎
Python3 迭代器与生成器 | 菜鸟教程
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值