首页 > 代码库 > 装饰器、生成器、迭代器、及python中内置函数的使用

装饰器、生成器、迭代器、及python中内置函数的使用

装饰器、生成器、迭代器、及python中内置函数的使用

一、 装饰器

1、 装饰器的概述

(1)概述:装饰器本质就是函数,主要用来装饰其他函数,为其他函数添加附加功能。

(2)使用装饰器的原则

   1)不能修改被装饰的函数的源代码

   2)不能修改被装饰的函数的调用方式

(3)装饰器原理:函数即“变量”、高阶函数、嵌套函数

2、使用装饰器的原因

(1)传统的多个函数模块修改需要同时修改多个函数、如果函数过多,则修改不方便。

   如下,如果想要在每个函数中开头结尾分别输入内容,则需要在每个函数开头结尾加入需要输出的内容。

def f1():
    print("F1")

def f2():
    print("F2")

........................

def f100():
    print("F100")

在开头结尾分别加入输出内容:

def f1():
print("head")
    print("F1")
print("end")

def f2():
print("head")
    print("F2")
print("end")

........................

def f100():
print("head")
    print("F100")
print("end")

(2)通过装饰器可以在调用函数前或者调用函数后定义一些功能让函数去执行。如果通过装饰器去修改上面函数,只需要再写一个装饰器函数,在需要的函数前通过“@functionname”调用即可

通过装饰器修改函数内容:

def outer(func):
    def inner():
        print(‘log‘)
        ret = func()
        print(‘after‘)
        return ret
    return inner()

@outer
def f1():
    print("F1")
    
@outer
def f2():
    print("F2")
    
@outer
def f100():
    print("F100")

3、使用装饰器前注意事项

(1)如果定义两个相同的函数,调用函数时,函数指针会指向最后定义的一个函数:

Author:Dayi123
def f1():
    print(123)

def f1():
    print(456)

f1()           #打印第二个f1函数

(2)定义两个函数,如果通过f2调用f1的函数名,调用的是整体f1

def f1():
    print(‘123‘)

def f2(xxx):
    xxx()

f2(f1)         # 调用的是整体f1

4、装饰器的调用

(1)装饰器的用法:@ + 函数名

(2)装饰器的功能

   1)自动执行outer函数并且将其下面的函数名f1当做参数传递

   2)将outer函数的返回值,重新赋值给f1

装饰器用法举例:

def outer(func):
    def inner():
        print("before")
        func()
        print(‘after‘)
    return inner()

@outer
def f1():
    print("F1")

3)装饰器流程之返回值

一个完整的装饰器如下:

def outer(func):
    def inner():
        print(‘before‘)
        r = func()
        print(‘after‘)
        return r #装饰器执行时没有返回值,默认返回NOLL,此处将函数f1的执行结果赋 
                    值给r,再返回给f1
    return inner

@outer
def f1():
    print("F1")
    return "hello"
s = f1()
print(s)

(4)装饰器流程之参数

   1)单个参数:

def outer(func):
    def inner(a):      #当函数中有参数时,装饰器中也应该加参数,以接受函数中的参数
        print(‘before‘)
        r = func(a)
        print(‘after‘)
        returnr
    return inner
@outer
def f1(age):
    print(age)
    return "hello"
s = f1(‘fafafa‘)
print("返回值:",s)

  2)两个或两个以上的参数:如果函数中存在两个或者两个以上的参数时,装饰器中就需要用万能参数接受函数传递的参数

def outer(func):
    def inner(*args, **kwargs): #当函数中存在两个及以上参数时,装饰器中应该用万能参数去接受
                                 函数传递的参数
        print(‘before‘)
        r = func(*args, **kwargs)   #此处应该也用万能参数
        print(‘after‘)
        return r
    return inner
@outer
def f1(age, name):
    print(age)
    print(name)
    return "hello"
s = f1(24,"dayi")

(3)装饰器应用案例——用户管理程序:

LOGIN_USER = {"is_login":False}      #此处用于标记用户是否登录

def outer(func):
    def inner(*args, **kwargs):
        if LOGIN_USER[‘is_login‘]:  #如果用户已经登录,则执行下面语句
            r = func()
            return r
        else:                       #如果用户没有登录,则执行下面语句
            print("请登录")
    return inner

@outer
def oreder():
    print("欢迎%s登录" % LOGIN_USER[‘current_user‘])

@outer
def changepwd():
    print("欢迎%s登录" % LOGIN_USER[‘current_user‘])

@outer
def manager():
    print("欢迎%s登录" % LOGIN_USER[‘current_user‘])

def login(user, pwd):
    if user == "dayi123" and pwd == "dayi123":
        LOGIN_USER[‘is_login‘] = True
        LOGIN_USER[‘current_user‘] = user
        manager()

def main():
    while True:
        inp = input("1,后台管理;2,登录")
        if inp == ‘1‘:
            manager()
        elif inp == ‘2‘:
            username = input("请输入用户名")
            pwd = input("请输入密码")
            login(username, pwd)

main()

5、用装饰器实现不能的页面采用不同的认证方式

import time
user,passwd = ‘dayi123‘,‘123456‘
def auth(auth_type):         # 再加一层函数,用于接受auth_type
    print("auth func:",auth_type)
    def outer_wrapper(func):#接受装饰的函数
        def wrapper(*args, **kwargs):    #接受装饰函数的参数
            print("wrapper func args:", *args, **kwargs)
            if auth_type== "local":    #如果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)  # from home
                    print("---after authenticaion ")
                    return res
                else:
                    exit("\033[31;1mInvalid username or password\033[0m")
            # 如果auth_type类型为ldap,则从此处认证
            elif auth_type == "ldap":
                print("ldap auhciation.....................")

        return wrapper
    return outer_wrapper

def index():
    print("welcome to index page")
@auth(auth_type="local") #home = wrapper()
def home():
    print("welcome to home  page")
    return "fromhome"

@auth(auth_type="ldap")
def bbs():
    print("welcome to bbs  page")

index()
print(home())#wrapper()
bbs()

三、生成器

1、列表生成式

a = []
for i in range(10):
    a.append(i*2)
#相当于
print(a)
a = [ i*2 for  i in range(10)]
print(a)

2、生成器

(1)生成器:一边生成一遍计算的一种机制

(2)列表生成式和生成器:

#列表生成式
a = [ i*2 for  iin range(100000000) ]  #用列表生成器生成多个元素是,会一次生成
print(a)                                #列表生成器生成后会全部打印出来
print(a[100])                           #由于已经生成放在了内存中,所以会打印出来

#生成器
b = ( i*2 for  iin range(100000000) )  #列表生成器生成时没有真正生成
print(b)                                #没有真正生成,所以不能打印
# print(b[1000])                        #没有生成,所以不能切片
print()
for i in b:                             #只有在调用时才生成
    if i <20:
        print(i)
        continue
    else:
        break
ret = b.__next__()                     #调用for循环后的下一个元素
print(ret)                             #打印
ret2 = b.__next__()
print(ret2)

(3)用函数生成生成器

#斐波拉契数列用列表生成式写出来
deffib(max): #10
    n, a, b = 0, 0, 1
    while n < max: #n<10
        print(b)              #执行此函数,则会把所有值一次性打印出来
        a, b = b, a + b
        n = n + 1
    # return ‘---done---‘
g =fib(60)
 
#把斐波拉契数列中的print变为yield,则这个函数变为生成器:
deffib(max):
    n, a, b = 0, 0, 1
    while n < max: #n<10
        yield b        #变为生成器后,则不会一次性打印出来,每调用一次,则打印一次
        a, b = b, a + b
        n = n + 1
    return ‘---done---‘
f=fib(10)
#使用一次调用一次
print(f.__next__())    #每调用一次则打印一次,如果调用次数大于生成数量则会报错
print(f.__next__())
print(f.__next__())
print(f.__next__())

注:此处的函数和生成器的区别:

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

(4)把函数改成生成器后,通过for循环来迭代:

def fib(max): #10
    n, a, b = 0,0,1
    while n <max: #n<10
        yield b                 #yield保存了函数的终端状态
        a, b= b, a + b
        n = n + 1
    return ‘---done---‘
 
#通过for循环来调用,拿不到返回值
for n in fib(19):       #通过for循环来调用,但是拿不到返回值
    print(n)
 
#如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中
g =fib(60)
whileTrue:
    try:                       #捕获StopIteration错误,同时拿到返回值
        x = next(g)             #next()为内置的方法,相当于__next__()
        print(‘g:‘, x)
    except StopIteration as e:
        print(‘Generator return value:‘,e.value)
       break

四、迭代器

1、可迭代对象(Interable):

(1)概述:可直接作用于for循环的对象统称为可迭代对象(主要包括集合数据类型,如列表、元组、字典、集合、字符串等和生成器类型)。

(2)判断一个对象是否是可迭代对象的方法:isinstance()

   使用之前需要导入模块 :fromcollection import Iterable

   判断一个对象是否可循环:isinstance([].Iterable)

2、迭代器

(1)概述:迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这使得它特别适合用于遍历一些巨大的或是无限的集合。

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

(3)判断一个对象是否是迭代器对象:isinstance()

   用法:使用之前导入模块:from collections import Iterator

       判断一个对象是否是迭代器:isinstance([].Iterator)

(3)特点:

   1)访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容

   2)不能随机访问集合中的某个值 ,只能从头到尾依次访问

   3)访问到一半时不能往回退

   4)便于循环比较大的数据集合,节省内存

   5)和函数一起使用:可以使函数中断并保存函数的中断状态

   6)生成器都是Iterator对象,但list,dict,虽然是可迭代对象(Iterable),却不是迭代器(Iterator),但list,dict,str等可迭代对象可以通过iter()函数变成迭代器

3、用法举例:

def myrange(arg):
    start = 0
    while True:
        if start >arg:
            return
        yield  start
        start += 1

ret = myrange(10)
for item in ret:           #利用迭代器调用生成器生成的内容
    print(item)

4、xrange举例(xrange)将列表变成迭代器(Python2中)

>>>xrange(100000)
xrange(100000)
>>>a = xrange(1000000)          #利用xrange生成一个列表
>>>a[1]
1

5、利用iter()将列表转换成迭代器案例:

>>>a = range(10)
>>>a = iter(a)                  #将生成的列表a转化成迭代器
>>>print(a.__next__())
0
>>>print(a.__next__())
1
>>>print(a.__next__())
2

五、 Python内置函数的应用举例

1、abs()、bool()、all()、any()、bin()、oct()、hex()的使用

n = abs(-1)             #abs() 用户去绝对值
print(n)
print(bool(0))          #对于bool(),只要里面传的是"0","None","""","[]","()"则返回False
n1 = all([1,2,3,4])     #只要里面有一个bool()中返回Falsh,则返回False,及所有为真则为真
print(n1)
n2 = any(( 0,(),1))     #只要有一个为真则为真
print(n2)
print(bin(5))           #将十进制转化成二进制
print(oct(5))           #将十进制转化成八进制
print(hex(15))          #将十进制转换成十六进制

2、bytes()的使用

#bytes()  #将需要的字符转换成字节类型
s = "大易"
n = bytes(s,encoding=‘utf-8‘)
print(n)
n1 = bytes(s,encoding=‘gbk‘)
print(n1)#将字节转化成字符串
new_str = str(bytes("大易",encoding=‘utf-8‘),encoding=‘utf-8‘)
print(new_str)

3、callable()、chr()、ord()、compile()、exec()、eval()的使用

#callable()    #用来检测传的值是否可以被执行、被调用
#chr()         #打印ascii吗中数字对应的符号
r = chr(65)
print(r)
#ord()        打印ascii码中字符对应的数字
n = ord("a")
print(n)
#compile()    将字符串编译成Python代码
s = "print(123)"
r = compile(s,"<string>","exec") #exec为编译成机器码模式,single为单行模式,exec为表达式模式
print(r)
#exec()为执行Python代码或字符串
exec(r)        #exec执行Python代码
#eval()        #将字符串转化成表达式去执行,并拿到执行结果
m = "8*8"
ret = eval(m)
print(ret)

4、dir()、help()、divmod()、isinstance()的使用

#dir()     快速查看一个对象提供了那些功能(内置方法)
print(dir(list))
#help()   查看帮助
help(list)
#divmod()
r = divmod(97, 10)    #得到97除10的商和余数,得到一个列表
print(r)
print(r[0])
print(r[1])
#isinstance()         用来判断对象是否是某个类的实例
s = [11,22,33]
r = isinstance(s,list)  #判断s是不是列表的实例
print(r)

5、filter()的使用

#filter 用来做过滤,函数返回True,将元素添加到结果中
#filter用法   filter(函数, 可迭代的对象)
def f2(a):
    if a>22:
        return True
li = [11,22,33,44,55,66,77]
ret = filter(f2, li)
print(list(ret))            #只打印大于22的数字#用lambda去实现
li = [11,22,33,44,55]
result = filter(lambda a: a > 33, li)
print(list(result))

6、map()的使用

#map()  批量的数据做统一的操作,将函数的返回值添加到结果中
# 用法 map(函数,可迭代的对象(可以for循环的东西))#传统的实现方法
li = [22,33,44,55]
def f1(args):
    result = []
    for i in args:
        result.append(100+i)
    return result
r = f1(li)
print(list(r))
#用map去实现
def f2(a):
    return a + 200
result = map(f2, li)
print(list(result))
#用map+lambda去实现
result2 = map(lambda a: a + 300, li)
print(list(result2))    #打印运算后的列表#也可以用for循环一个一个去打印
Result3 = map(lambda a: a*a, range(10))  #相当于列表生成式[ i*i for i in range(10)]
# print(list(result3))
for i in result3:
    print(i)#reduce用法 
import functools   #导入模块
res = functools.reduce( lambda x,y:x*y,range(1,10 )) #计算1到10的乘积
print(res)

Map用法2:

#仅在pyton2中使用,Python3中range(1,10)已变成迭代器
a = range(5,10)
b = range(10,20)
print map(None,a,b)    #打印a、b生成的元组对,a或b中元素不够时,会用None替代

输出结果:[(5, 10), (6, 11), (7, 12), (8, 13), (9, 14), (None, 15), (None,16), (None, 17), (None, 18), (None, 19)]

7、globals()、locals()、len()、hash()的使用

#globals()  #代表所有的全局变量,key-value格式
#locals()   代表所有的局部变量
NAME = "dayi123"
def show():
    a = 123
    c = 456
    print(locals())
    print(globals())
show()
#hash()
s = "dayi"   #生成hash值,一般用于字典的“key”保存
print(hash(s))

#len()  查看长度
s = "刘毅"
print(len(s))                     #计算字符串的长度
b = bytes(s, encoding="utf-8")   #转换成字节,计算字节的长度
print(len(b))

8、max(),sum(),min()、pow、sorted()、zip()、round()的使用

#max(),sum(),min()分别为求最大值、求和、求最小值
r = ([11,22,33,1,40])
print(max(r))
#pow  求指数
w = pow(2, 10)
print(w)
#reverse()  翻转,跟列表翻转一样
#round    #四舍五入,取整数
n = round(1.8)
print(n)n2 = round(1.234,2)    #保留两位小数
print(n2)
#sorted() 排序
li = [21,22,4,55]
print(sorted(li))  #作用同li.sort() 一样
#zip  将列表合并到一起,将第一个元素合并成第一个元素,第二个元素合并成第二个元素
l1 = ["dayi",11,22,33]
l2 = ["is",11,22,33]
l3 = ["nb",11,22,33]
haha = zip(l1, l2, l3)
temp = list(haha)[0]
print(temp)
ret = ‘ ‘.join(temp)
print(ret)


本文出自 “dayi123” 博客,请务必保留此出处http://dayi123.blog.51cto.com/12064061/1918665

装饰器、生成器、迭代器、及python中内置函数的使用