[转载] python迭代器、生成器和装饰器

参考链接: 有效地在Python中使用迭代

文章目录

 生成器生成器表达式(generator expression)通过使用yield关键字定义生成器并行前戏高潮

  

  迭代器迭代器概述iter()函数 创建迭代器创建一个迭代器(类)内置迭代器工具count无限迭代器cycle 无限迭代器,从一个有限序列中生成无限序列:itertools的子模块 islice 控制无限迭代器输出的方式

  

  装饰器高阶函数嵌套函数高阶函数+嵌套函数 = 装饰器类装饰器带参数的decorator实例---登录认证

 

 

 

生成器 

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。 

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。 

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator: 

生成器表达式(generator expression) 

L = [x + 1 for x in range(10)]

print(L)

 

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

 

列表生成式复习 

实现列表元素加1,列表生成式与其它方法比较: 

#普通方法1

b = []

for i in range(10):

    b.append(i+1)

print(b)

 

#普通方法2

a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

for index,i in enumerate(a):

    a[index] +=1

print(a)

 

#map,lambda

a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

a = map(lambda x:x+1, a)

print(list(a))

 

 

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

 

g = (x + 1 for x in range(10))

print(g)

 

<generator object <genexpr> at 0x7fe03ad859a8>

 

创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。 

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢? 

如果要一个一个打印出来,可以通过next()函数(or __next__())获得generator的下一个返回值: 

next(g)

 

1

 

next(g)

 

2

 

next(g)

 

3

 

g.__next__()

 

4

 

g.__next__()

 

5

 

generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误 

上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象: 

g = (x * x for x in range(10))

for n in g:

    print(n,end=";")

 

0;1;4;9;16;25;36;49;64;81;

 

所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误 

通过使用yield关键字定义 

生成器对象是通过使用yield关键字定义的函数对象,因此,生成器也是一个函数。生成器用于生成一个值得序列,以便在迭代器中使用。 

"""

第一是直接作为脚本执行,

第二是import到其他的python脚本中被调用(模块重用)执行。

因此if __name__ == '__main__': 的作用就是控制这两种情况执行代码的过程,

在if __name__ == '__main__':下的代码只有在第一种情况下(即文件作为脚本直接执行)才会被执行,而import到其他脚本中是不会被执行的。

"""

 

def myYield(n):

    while n>0:

        print('开始生成。。。')

        yield n

        print('完成一次。。。')

        n -= 1

if __name__ == '__main__':

    a = myYield(3)

    print('已经实例化生成器对象')

#     a.__next__()

#     print('第二次调用__next__()方法:')

#     a.__next__()

 

已经实例化生成器对象

 

yield 语句是生成器中的关键语句,生成器在实例化时并不会被执行,而是等待调用其__next__()方法才开始运行。并且当程序运行完yield语句后就会“吼(hold)住”,即保持当前状态且停止运行,等待下一次遍历时才恢复运行。 

程序运行的结果中的空行后的输出“已经实例化生成器对象”之前,已经实例化了生成器对象,但生成器并没有运行(没有输出‘开始生成’)。当第一次手工调用__next__()方法之后,才输出‘开始生成’,标志着生成器已经运行,而在输出‘’第二次调用__next__()方法‘’之前并没有输出‘完成一次’,说明yield语句运行之后就立即停止了。而第二次调用__next__()方法之后,才输出‘完成一次’,说明生成器的回复运行是从yield语句之后开始运行的 

return_value = a.__next__()

print(return_value)

 

开始生成。。。

3

 

print('第二次调用__next__()方法:')

 

第二次调用__next__()方法:

 

return_value = a.__next__()

print(return_value)

 

完成一次。。。

开始生成。。。

2

 

著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到: 

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易: 

def fib(max):

    n, a, b = 0, 0, 1

    while n < max:

        print(b)

        a, b = b, a + b

        n = n + 1

    return 'done'

 

注意,赋值语句: 

a, b = b, a + b

 

相当于: 

t = (b, a + b) # t是一个tuple

a = t[0]

b = t[1]

 

上面的函数可以输出斐波那契数列的前N个数: 

fib(5)

 

1

1

2

3

5

 

 

 

 

 

'done'

 

上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了: 

def fib(max):

    n,a,b = 0,0,1

    while n < max:

        #print(b)

        yield  b

        a,b = b,a+b

        n += 1

    return 'well done' 

 

这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。 

f = fib(5)

print(f)

print(list(f))

 

#重新实例化生成器对象

f = fib(5)

 

<generator object fib at 0x7fe038493840>

[1, 1, 2, 3, 5]

 

print(f.__next__())

print(f.__next__())

print("干点别的事")

print(f.__next__())

print(f.__next__())

print(f.__next__())

print(f.__next__())

 

1

1

干点别的事

2

3

5

 

 

 

---------------------------------------------------------------------------

 

StopIteration                             Traceback (most recent call last)

 

<ipython-input-18-9609f54647c6> in <module>

      5 print(f.__next__())

      6 print(f.__next__())

----> 7 print(f.__next__())

 

 

StopIteration: well done

 

用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中: 

g = fib(6)

while True:

    try:

        x = next(g)

        print('g:', x)

    except StopIteration as e:

        print('Generator return value:', e.value)

        break

 

g: 1

g: 1

g: 2

g: 3

g: 5

g: 8

Generator return value: well done

 

from itertools import islice

def fib():

    a,b = 0,1

    while True:

        yield b

        a,b = b,a+b

f = fib()

print(list(islice(f ,0,10)))

 

[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

 

生成器在Python中是一个非常强大的编程结构,可以用更少地中间变量写流式代码,此外,相比其它容器对象它更能节省内存和CPU,当然它可以用更少的代码来实现相似的功能。现在就可以动手重构你的代码了,但凡看到类似 

def something():

    result= []

    for ... in ...:

        result.append(x)

        return result

 

都可以用生成器函数来替换: 

def iter_something():

    result = []

    for ... in ...:

        yield x

 

杨辉三角 

期待输出: 

[1]

[1, 1]

[1, 2, 1]

[1, 3, 3, 1]

[1, 4, 6, 4, 1]

[1, 5, 10, 10, 5, 1]

[1, 6, 15, 20, 15, 6, 1]

[1, 7, 21, 35, 35, 21, 7, 1]

[1, 8, 28, 56, 70, 56, 28, 8, 1]

[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]

 

def triangles():

    result = [1]

    while True:

        yield result

        result = [1] + [result[i] + result[i+1] for i in range(len(result)-1)] + [1]

 

n = 0

results = []

for t in triangles():

    print(t)

    results.append(t)

    n = n + 1

    if n == 10:

        break

if results == [

    [1],

    [1, 1],

    [1, 2, 1],

    [1, 3, 3, 1],

    [1, 4, 6, 4, 1],

    [1, 5, 10, 10, 5, 1],

    [1, 6, 15, 20, 15, 6, 1],

    [1, 7, 21, 35, 35, 21, 7, 1],

    [1, 8, 28, 56, 70, 56, 28, 8, 1],

    [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]

]:

    print('测试通过!')

else:

    print('测试失败!')

 

 

[1]

[1, 1]

[1, 2, 1]

[1, 3, 3, 1]

[1, 4, 6, 4, 1]

[1, 5, 10, 10, 5, 1]

[1, 6, 15, 20, 15, 6, 1]

[1, 7, 21, 35, 35, 21, 7, 1]

[1, 8, 28, 56, 70, 56, 28, 8, 1]

[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]

测试通过!

 

生成器并行 

前戏 

def gen():

    a = yield 1

    print('yield a % s' % a)

    b = yield 2

    print('yield b % s' % b)

    c = yield 3

    print('yield c % s' % c)

    return "happy ending"

 

 

r = gen()

x = next(r)

print('next x %s' % x)

y = r.send(10)

print('next y %s' %y)

z = next(r)

print('next z %s' % z)

try:

    a = next(r)

except StopIteration as e:

    print(e)

 

 

next x 1

yield a 10

next y 2

yield b None

next z 3

yield c None

happy ending

 

运行过程说明: 

第一步:r = gen(),实例化一个生成器对象第二步:调用next() ,遇到yield 暂停,返回值1,赋值给x第三步:打印x的值第四步:传值10,在暂停处接受值10,赋值给a,继续运行,打印a的值,遇到第二个yield,暂停,返回值2,赋值给y第五步:打印y的值第六步:调用next() ,打印b值,遇到第三个yield暂停,返回值3,赋值给z第七步:打印z值第八步:调用next(),打印c的值,报StopIteration错误,用try。。。except捕获错误 

高潮 

import time

import random

 

food = ["韭菜鸡蛋","猪肉白菜","猪肉荠菜","羊肉白菜","猪肉大葱","虾仁海鲜"]

 

 

def consumer(name):

    print("%s 准备吃包子啦!" %name)

    while True:

        baozi = yield 'n'

        print("[%s]馅包子来了,被[%s]吃了!" %(baozi,name))

 

        

def producer(name):

    c1 = consumer('大儿子')

    c2 = consumer('小儿子')

    c1.__next__()

    c2.__next__()

    print("%s开始准备做包子啦" % name)

    for i in range(6):

        print("第%d次做了%s个包子"%(i+1,len(food)))

        time.sleep(random.randint(1,3))

        f1 = food[i]

        c1.send(f1)

        food.append(f1)

        random.shuffle(food)

        c2.send(food[i])

        

producer('老子')

 

大儿子 准备吃包子啦!

小儿子 准备吃包子啦!

老子开始准备做包子啦

第1次做了6个包子

[韭菜鸡蛋]馅包子来了,被[大儿子]吃了!

[韭菜鸡蛋]馅包子来了,被[小儿子]吃了!

第2次做了7个包子

[韭菜鸡蛋]馅包子来了,被[大儿子]吃了!

[猪肉大葱]馅包子来了,被[小儿子]吃了!

第3次做了8个包子

[韭菜鸡蛋]馅包子来了,被[大儿子]吃了!

[猪肉大葱]馅包子来了,被[小儿子]吃了!

第4次做了9个包子

[猪肉白菜]馅包子来了,被[大儿子]吃了!

[羊肉白菜]馅包子来了,被[小儿子]吃了!

第5次做了10个包子

[虾仁海鲜]馅包子来了,被[大儿子]吃了!

[韭菜鸡蛋]馅包子来了,被[小儿子]吃了!

第6次做了11个包子

[韭菜鸡蛋]馅包子来了,被[大儿子]吃了!

[虾仁海鲜]馅包子来了,被[小儿子]吃了!

 

迭代器 

迭代器概述 

可以直接作用于for循环的数据类型有以下几种: 

一类是集合数据类型,如list,tuple,dict,set,str等一类是generator ,包括生成器和带yeild的generator function 

这些可以 直接作用于for循环的对象统称为可迭代对象:Iterable 

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator 

a = [i for i in range(10)]

next(a)

 

---------------------------------------------------------------------------

 

TypeError                                 Traceback (most recent call last)

 

<ipython-input-23-8981550fe3e0> in <module>

      1 a = [i for i in range(10)]

----> 2 next(a)

 

 

TypeError: 'list' object is not an iterator

 

list,dict,str虽然是Iterable,却不是Iterator 

from collections import Iterator

from collections import Iterable

print(isinstance(a,Iterator))

print(isinstance(a,Iterable))

print(isinstance({},Iterable))

print(isinstance('abc',Iterable))

 

False

True

True

True

 

生成器就是一个迭代器 

a = (i for i in range(10))

print(next(a))

print(isinstance(a,Iterator))

 

0

True

 

iter()函数 创建迭代器 

iter(iterable)#一个参数,要求参数为可迭代的类型 

把list、dict、str等Iterable变成Iterator可以使用iter()函数: 

print(isinstance({},Iterator))

print(isinstance('abc',Iterator))

print(isinstance(iter({}),Iterator))

print(isinstance(iter('abc'),Iterator))

 

False

False

True

True

 

你可能会问,为什么list、dict、str等数据类型不是Iterator? 

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。 

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。 

小结 

 凡是可作用于for循环的对象都是Iterable类型;  凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;  集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。  

Python的for循环本质上就是通过不断调用next()函数实现的,例如: 

for x in [1, 2, 3, 4, 5]:

    print(x,end=',')

 

1,2,3,4,5,

 

实际上完全等价于: 

# 首先获得Iterator对象:

it = iter([1, 2, 3, 4, 5])

# 循环:

while True:

    try:

        # 获得下一个值:

        x = next(it)

        print(x,end=',')

    except StopIteration:

        # 遇到StopIteration就退出循环

        break

 

 

1,2,3,4,5,

 

创建一个迭代器(类) 

把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__() 。 

如果你已经了解的面向对象编程,就知道类都有一个构造函数,Python 的构造函数为 __init__(), 它会在对象初始化的时候执行 

__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。 

from itertools import islice

class Fib:

    def __init__(self):

        self.prev = 0

        self.curr = 1

    def __iter__(self):

        return self

    def __next__(self):

        self.prev,self.curr = self.curr,self.prev+self.curr

        return self.curr

f = Fib()

print(list(islice(f ,0,10)))

 

[1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

 

Fib既是一个可迭代对象(因为它实现了 __iter__方法),又是一个迭代器(因为实现了 __next__方法) 

StopIteration 

StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 next() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。 

在 20 次迭代后停止执行: 

class MyNumbers:

    def __init__(self):

        self.a = 1

    

    def __iter__(self):

        return self

 

    def __next__(self):

        if self.a <= 20:

            x = self.a

            self.a += 1

            return x

        else:

            raise StopIteration

 

myclass = MyNumbers()

myiter = MyNumbers()

# myiter = iter(myclass)

 

for x in myiter:

    print(x,end=",")

 

 

1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,

 

内置迭代器工具 

比如 itertools 函数返回的都是迭代器对象 

count无限迭代器 

from itertools import count

counter = count(start=10)  

print(next(counter))

print(next(counter)) #python内建函数next()对itertools创建的迭代器进行循环

 

10

11

 

cycle 无限迭代器,从一个有限序列中生成无限序列: 

from itertools import cycle

colors = cycle(['red','black','blue'])

print(next(colors))

print(next(colors))

print(next(colors))

print(next(colors))

print(next(colors))  

 

red

black

blue

red

black

 

itertools的子模块 islice 控制无限迭代器输出的方式 

islice的第二个参数控制何时停止迭代,迭代了11次后停止,从无限的序列中生成有限序列: 

from itertools import count

counter = count(start=10)

i=4

print(next(counter))

while i > 0:

    print(next(counter))

    i -= 1

 

10

11

12

13

14

 

from itertools import count

for i in count(10):

    if i > 14 :

        break

    else:

        print(i)

 

10

11

12

13

14

 

from itertools import islice

from itertools import count

for i in islice(count(10),5):

    print(i)

 

10

11

12

13

14

 

from itertools import cycle

from itertools import islice

colors = cycle(['red','black','blue'])

limited = islice(colors,0,4)

for x in limited:

    print(x)

 

red

black

blue

red

 

装饰器 

器,代表函数的意思 

 装饰器:本质是函数(装饰其他函数)就是为其他函数添加附加功能 

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

原则: 

1 不能修改被装饰的函数的源代码2 不能修改被装饰的函数的调用方式 

实现装饰器知识储备: 

 1 函数即“”变量“”  2 高阶函数 a 把一个函数名当做实参传给另一个函数 b 返回值中包含函数名  

高阶函数 

import time

def bar():

    time.sleep(3)

    print('in the bar')

def test2(func):

    print(func)

    return func

 

print(test2(bar)) #调用test2,打印bar的内存地址,返回bar的内存地址,又打印

 

<function bar at 0x7fe03849e620>

<function bar at 0x7fe03849e620>

 

bar=test2(bar) # 返回的bar的内存地址,赋值给bar

bar() #run bar

 

<function bar at 0x7fe03849e620>

in the bar

 

嵌套函数 

x = 0

def grandpa():

    x = 1

    print(x)

    def dad():

        x =2

        print(x)

        def son():

            x =3

            print(x)

        son()

    dad()

 

grandpa()

 

1

2

3

 

高阶函数+嵌套函数 = 装饰器 

import time

def timer(func): #timer(test1) func=test1

    def deco(*args,**kwargs):  #非固定参数

        start_time=time.time()

        func(*args,**kwargs) #run test1()

        stop_time = time.time()

        print("the func run time is %s" %(stop_time-start_time))

    return deco

@timer #test1=timer(test1) 把deco的内存地址返回给test1

def test1():

    time.sleep(1)

    print('in the test1')

 

@timer # test2 = timer(test2) = deco test2(name) =deco(name)

def test2(name,age):

    print("test2:",name,age)

 

test1() #实际上是在执行deco

test2("alex",22)

 

in the test1

the func run time is 1.001246452331543

test2: alex 22

the func run time is 0.00011372566223144531

 

类装饰器 

没错,装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__方法 

 

class Foo(object):

    def __init__(self, func):

        self._func = func

 

    def __call__(self):

        print ('class decorator runing')

        self._func()

        print ('class decorator ending')

 

@Foo

def bar():

    print ('bar')

bar()

 

 

class decorator runing

bar

class decorator ending

 

装饰器可以把与业务逻辑无关的代码抽离出来,让代码保持干净清爽,而且装饰器还能被多个地方重复利用。比如一个爬虫网页的函数,如果该 URL 曾经被爬过就直接从缓存中获取,否则爬下来之后加入到缓存,防止后续重复爬取。 

def web_lookup(url, saved={}):

    if url in saved:

        return saved[url]

    page = urllib.urlopen(url).read()

    saved[url] = page

    return page

 

pythonic 

import urllib.request as urllib # py3

def cache(func):

    saved= {}

    def wrapper(url):

        if url in saved:

            return saved [url]

        else:

            page = func(url)

            saved [url] = page

            return page

    return wrapper

    

@cache

def web_lookup(url):

    return urllib.urlopen(url).read()

 

用装饰器写代码表面上感觉代码量更多,但是它把缓存相关的逻辑抽离出来了,可以给更多的函数调用,这样总的代码量就会少很多,而且业务方法看起来简洁了。 

带参数的decorator 

def log(text):

    def decorator(func):

        def wrapper(*args, **kw):

            print('%s %s():' % (text, func.__name__))

            return func(*args, **kw)

        return wrapper

    return decorator

 

还差最后一步。因为我们讲了函数也是对象,它有__name__等属性,但你去看经过decorator装饰之后的函数,它们的__name__已经从原来的’now’变成了’wrapper’: 

@log('execute')

def now():

    print('2015-3-25')

    

now()

now.__name__

 

execute now():

2015-3-25

 

 

 

 

 

'wrapper'

 

因为返回的那个wrapper()函数名字就是’wrapper’,所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。 

不需要编写wrapper.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下: 

import functools

 

def log(text):

    def decorator(func):

        @functools.wraps(func)

        def wrapper(*args, **kw):

            print('%s %s():' % (text, func.__name__))

            return func(*args, **kw)

        return wrapper

    return decorator

 

 

@log('execute')

def now():

    print('2015-3-25')

    

now()

now.__name__

 

execute now():

2015-3-25

 

 

 

 

 

'now'

 

那么不带参数decorator,也是一样的 

import functools

 

def log(func):

    @functools.wraps(func)

    def wrapper(*args, **kw):

        print('call %s():' % func.__name__)

        return func(*args, **kw)

    return wrapper

 

实例—登录认证 

import functools

 

 

user,passwd = 'sun' ,'123'

def auth(auth_type):

    print("auth func:",auth_type)

    def decorator(func):

        @functools.wraps(func)

        def wrapper(*args,**kwargs):

            print('wrapper func args:',*args,**kwargs)

            if auth_type == 'local':

                username = input('Username:').strip()

                password = input("Password:").strip()

                if user == username and passwd == password:

                    print("\033[32;1mUser has passed authentication\033[0m")

                    res = func(*args, **kwargs) 

                    print("--after authentication--")

                    return res

                else:

                    exit("\033[31;1mInvalid username or password\033[0m")

            elif auth_type == 'ldap':

                res = func(*args, **kwargs)

                print("搞毛线ldap,不会。。。。")

                return res

 

        return wrapper

    return decorator

 

def index():

    print("welcome to index page")

 

@auth(auth_type='local')

def home():

    print("welcome to home page")

    return 'from home'

 

@auth(auth_type='ldap')

def bbs():

    print("welcome to bbs page")

 

 

index()

print(home())  #wrapper

bbs()

 

 

auth func: local

auth func: ldap

welcome to index page

wrapper func args:

Username:sun

Password:123

[32;1mUser has passed authentication[0m

welcome to home page

--after authentication--

from home

wrapper func args:

welcome to bbs page

搞毛线ldap,不会。。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/540468.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java中的starts_Java Math类静态double nextAfter(double starts,double direction)示例

java中的starts数学类静态double nextAfter(双向启动&#xff0c;双向) (Math Class static double nextAfter(double starts , double directions) ) This method is available in java.lang package. 此方法在java.lang包中可用。 This method is used to return the double …

Python 核心编程(第二版)——条件和循环

Python 中的 if 子句由三部分组成: 关键字本身&#xff0c;用于判断结果真假的条件表达式&#xff0c; 以及当表达式为真或者非零时执行的代码块。if 语句的语法如下: if expression: expr_true_suite 单个 if 语句可以通过使用布尔操作符 and , or 和 not实现多重判断条件或…

[转载] 【python魔术方法】迭代器(__iter__和__next__)

参考链接&#xff1a; Python __iter __()和__next __()| 将对象转换为迭代器 文章目录 __iter__ 和 __next__真正的迭代器总结 python里面有很多的以__开始和结尾的函数&#xff0c;利用它们可以完成很多复杂的逻辑代码&#xff0c;而且提高了代码的简洁性&#xff0c;本文主…

Silverlight 异步单元测试

Silverlight 中的很多操作都是异步的&#xff0c;很多情况下要求单元测试也是异步的&#xff0c;但是介绍异步单元测试的文档很少。通过对 Silverlight Toolkit 中的 Microsoft.Silverlight.Testing 和 Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight 这两个文件…

网络拓扑 令牌环网 以太网_以太网连接中网络拓扑的类型及其框架 以太网技术...

网络拓扑 令牌环网 以太网A topology explains how physically the network is designed or what is the structure of the network. These designs are both physical and logical. There are many network topologies 4 like Bus, Star, Ring, and Mesh. But only two types …

Wafer晶圆封装工艺介绍

芯片封装的目的&#xff08;The purpose of chip packaging&#xff09;: 芯片上的IC管芯被切割以进行管芯间连接&#xff0c;通过引线键合连接外部引脚&#xff0c;然后进行成型&#xff0c;以保护电子封装器件免受环境污染&#xff08;水分、温度、污染物等&#xff09;&…

[转载] Python中的解析式和生成器表达式

参考链接&#xff1a; Python | 生成器表达式 解析式和生成器表达式 列表解析List Comprehension 语法 [返回值 for 元素 in 可迭代对象 if 条件]使用中括号[],内部是for循环&#xff0c;if条件语句可选&#xff0c;会返回一个新的列表 列表解析试优点 编译器会优化&…

java 数字字母进位_使用带有进位的8085微处理器将两个8位数字相乘

java 数字字母进位Problem statement: 问题陈述&#xff1a; Multiplication of two 8 bits numbers using 8085 microprocessor with carry. 使用带有进位的8085微处理器将两个8位数字相乘。 Algorithm: 算法&#xff1a; Load HL pair with initial data using LHLD comma…

[转载] Python3.0中普通方法、类方法和静态方法的比较

参考链接&#xff1a; Python中的类方法与静态方法 一、语法区别 刚接触Python中的面向对象&#xff0c;对于类方法和静态方法难以区分&#xff0c;通过查找知乎、CSDN论坛&#xff0c;废了好大的劲思路才逐渐明朗&#xff0c;所以就总结顺便分享一下。 首先开始编辑代码 # 普…

iOS:个人浅谈工厂模式

一、什么是工厂方法&#xff1f; 正式的解释是&#xff1a;在基类中定义创建对象的一个接口&#xff0c;让子类决定实例化哪个类。工厂方法让一个类的实例化延迟到子类中进行。工厂方法要解决的问题是对象的创建时机&#xff0c;它提供了一种扩展的策略&#xff0c;很好地符合了…

scanf 输入十六进制_使用C语言中的scanf()在字符变量中输入十进制,八进制和十六进制值...

scanf 输入十六进制Here, we will declare an unsigned char variable and input different formats value like decimal format, octal format and hexadecimal format. 在这里&#xff0c;我们将声明一个无符号的char变量&#xff0c;并输入不同格式的值&#xff0c;例如十进…

[转载] Python中pass的作用

参考链接&#xff1a; 如何在Python中编写空函数&#xff1f;请使用 pass语句 空语句 do nothing保证格式完整保证语义完整 以if语句为例&#xff0c;在c或c/java中&#xff1a; if(true) ; //do nothing else { //do something } 对应于python就要这样写&#xff…

wrf 嵌套网格作用_在网格系统中使用响应列,嵌套列和偏移列 引导程序

wrf 嵌套网格作用介绍 (Introduction) In the previous article, we have learnt what is grid and grid system and how it works? Now, we will learn about how Responsive column, Nesting Columns and Offset Columns works and how to use them? If you have any doubt…

[看书笔记]《深入java虚拟机》——java体系结构(二)

java虚拟机的三种含义&#xff1a; - 抽象的规范 - 一个具体的实现 - 一个运行中的虚拟机实例 ---------------------java虚拟机的生命周期&#xff1a; java虚拟机实例的天职就是负责运行一个java程序。 启动一个java程序&#xff0c;一个虚拟机实例诞生了&#xff1b;程序关闭…

[转载] 【零基础学爬虫】python中的yield详解

参考链接&#xff1a; 什么时候在Python中使用yield而不是return python中的yield功能比较强大&#xff0c;什么意思呢&#xff1f;如果一个函数f内使用了yield关键词&#xff0c;那么该函数就可以这样使用&#xff1a; for item in f(***): **** 也就是包含yield关键词的函…

全新的membership框架Asp.net Identity(1)——.Net membership的历史

在Asp.net上&#xff0c;微软的membershop框架经历了Asp.net membership到Asp.net simple membership&#xff0c;再到现在的Asp.net Identity. 每一次改变&#xff0c;都使得验证框架更加的适应变化和可定制。这篇文章是Asp.net Identity系列的开篇&#xff0c;主要就membersh…

c语言100位整数变量声明_C ++程序动态声明一个整数变量并打印其内存地址

c语言100位整数变量声明Here, we will learn how we can declare an integer variable dynamically and how to print address of declared memory block? 在这里&#xff0c;我们将学习如何动态声明整数变量&#xff0c;以及如何打印声明的内存块的地址&#xff1f; In C pr…

[转载] python 函数返回多个值

参考链接&#xff1a; 在Python中返回多个值 &#xff08;廖雪峰Python教程学习笔记&#xff09; 函数体内部的语句在执行时&#xff0c;一旦执行到return&#xff0c;函数就执行完毕&#xff0c;并将结果返回。 如果没有return语句&#xff0c;函数执行完毕后也会返回结果…

二.编写第一个c#程序(注释,命名空间,类,Main方法,标识符,关键字,输入,输出语句,)...

复习编写一个控制台应用程序&#xff0c;目标是在控制台输出“Hello World” 1.第一步&#xff0c;打开Visual Studio 2012以上版本(我用的是VS 2015)&#xff0c;打开完成后出现以下界面 2.第二步&#xff0c;这时候就要新建一个解决方案了&#xff0c;创建解决方案可以直接点…

[转载] Python中定义函数,循环语句,条件语句

参考链接&#xff1a; Python中的局部函数 由于日常程序流中主要是三种结构&#xff1a;顺序&#xff0c;循环&#xff0c;条件&#xff0c;且往往需要自定义函数再调用&#xff0c; 因此今天想学习一下Python中关于定义函数、循环语句和条件语句的写法。 1.定义函数 区…