Python学习之四 装饰器

1. 装饰器:
2. 本质是函数 ,功能(装饰其他函数)就是为其他函数添加附加功能
3. 原则
1. 不能修改被装饰得函数的源代码
2. 不能修改被装饰的函数的调用方式
4 实现装饰器知识储备:
1.函数即变量
2.高阶函数
3.嵌套函数
高阶函数+嵌套函数= 装饰器
在函数体内用def去声明一个新的函数而不是调用

函数即变量
def bar():
    print('in the bar')
def foo():
    print('in the foo')
    bar()
foo()


def foo():
    print('in the foo')
    bar()
def bar():
    print('in the bar')
foo()

  

高阶函数
a: 把一个函数名当做实参传给另一个函数(不修改被装饰函数源代码的情况下为其添加功能)
b: 返回值中包含函数名(不修改函数的调用方式)
import time
def bar():
    time.sleep(2)
    print(' in the >>> bar')
def test1(func):
    star_time = time.time()
    print(func)
    func()
    stop_time = time.time()
    print('the func run time is %s' %(stop_time-star_time))
test1(bar)

  

b: 返回值中包含函数名(不修改函数的调用方式)
def bar():
    time.sleep(2)
    print('in the bar')

def test2(func):
    print(func)
    return func
bar = test2(bar)
bar()

  嵌套函数

def foo():
    print('in the bar')
    def bar():
        print('in the bar')
    bar()
foo()

  装饰器(1)

user,passwd = 'scott','abc123'
def auth(func):  # 装饰
    def wrapper(*args, **kwargs): #内嵌
        print('wrapper func args:', *args, **kwargs)
        username = input('username:').strip()
        password = input('password').strip()
        if user == username and passwd == password:
            print('\033[32;1m user has passed\033[0m')
            res = func(*args, **kwargs)
            print('----after---')
            return res
        else:
            exit('\033[32;1m error \033[0m')
    return wrapper

def index():
    print('welcom to index page')
@auth
def home():
    print('welcome to home')
    return "from home"
@auth
def bbs():
    print('welcom to bbs')
index()
print(home())
bbs()

  装饰器(2

user,passwd = 'scott','abc123'
def auth(auth_type):  # 装饰
    print('auth func',auth_type)
    def outer_wrapper(func): # 原来这里是第一层了 但是有了上一个 就往下移了一层
        def wrapper(*args, **kwargs):  # 内嵌
            print('wrapper func args:', *args, **kwargs)
            username = input('username:').strip()
            password = input('password').strip()
            if user == username and passwd == password:
                print('\033[32;1m user has passed\033[0m')
                res = func(*args, **kwargs)
                print('----after---')
                return res
            else:
                exit('\033[32;1m error \033[0m')

        return wrapper
    return outer_wrapper
def index():
    print('welcom to index page')
@auth(auth_type='local') # (auth_type='ldap')这里的参数直接传给auth(auth_type)
def home():
    print('welcome to home')
    return "from home"
@auth(auth_type='ldap')  # (auth_type='ldap')这里的参数直接传给auth(auth_type)
def bbs():
    print('welcom to bbs')
index()
print(home())
bbs()

  装饰器(3)

user,passwd = 'scott','abc123'
def auth(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':
                username = input('username:').strip()
                password = input('password').strip()
                if user == username and passwd == password:
                    print('\033[32;1m user has passed\033[0m')
                    res = func(*args, **kwargs)
                    print('----after---')
                    return res
                else:
                    exit('\033[32;1m error \033[0m')
            elif auth_type == 'ldap':
                print('buhui')
        return wrapper
    return outer_wrapper
def index():
    print('welcom to index page')
@auth(auth_type='local') # (auth_type='ldap')这里的参数直接传给auth(auth_type)
def home():
    print('welcome to home')
    return "from home"
@auth(auth_type='ldap')  # (auth_type='ldap')这里的参数直接传给auth(auth_type)
def bbs():
    print('welcom to bbs')
index()
print(home())
bbs()

  

迭代器和生成器

列表生成式 使代码更简洁
a = [1,2,3]
a = []
for i in range(10):
    a.append(i*2)
a = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 这种方式直接生成到内存里面

[ i*2 for i in range(10)]  一句顶三句
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
只有调用的时候才会生成相应的数据 不使用就不会生成数据 不能使用切片,下标的方式取数据 只能一个一个的取
 b = ( i*2 for i in range(100000000))
 for i in b:
    print(i)
可以使用__next__() 方法取值 只记住当前位置 只保留一个位置,只能向后走不能向前回去
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,
创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,
那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?
这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

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

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b  # a = b b=a + b
        n = n + 1
    return 'done'
fib(10)
仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,
推算出后续任意的元素,这种逻辑其实非常类似generator。

也就是说,上面的函数和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  # a = b b=a + b
        n = n + 1
    return 'done'
f = fib(10)
print(f.__next__())
print(f.__next__())
print("=====start loop====")
for i in f:
    print(i)
可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator
function。
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。 可循环的对象
可以使用isinstance()
判断一个对象是否是Iterable对象:
from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

  

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
可以使用isinstance()判断一个对象是否是Iterator对象:

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
把list、dict、str等Iterable变成Iterator可以使用iter()函数:
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
为什么list、dict、str等数据类型不是Iterator?

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

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

f.readlines 一行一行的读,把每一行当做一个列表
for line in f # 每一次print line就是取迭代一次next方法
josn
import json
把字典以json的方式存到test文件里面 内容为{"name": "scott", "age": 22}
info = {
    'name' : 'scott',
    'age' : 22
}
f = open('test','w')
print()
f.write(json.dumps(info))
f.close()

读取test文件里面的字典内容 结果会输出 22
import json
f = open('test','r')
date = json.loads(f.read())
print(date['age'])

  

import pickle
def sayhi(name):
    print("hello,", name)
info = {
    'name': 'scott',
    'age': 22,
    'func': sayhi
}
f = open("test.text", "wb")
pickle.dump(info, f)  # f.write( pickle.dumps( info) ) 是一样的
f.close()

import pickle
def sayhi(name):
    print("hello2,", name)
f = open("test.text", "rb")
data = pickle.load(f)  # data = pickle.loads(f.read())
print(data["func"]("scott"))

  3.0 能dump好多次

  但是不能load多次 只能是一次

所以以后使用的时候要做到 dump一次load一次

#import json

import pickle
def sayhi(name):
    print("hello,",name)
info = {
    'name': 'scott',
    'age': 22,
    'func': sayhi
}
f = open("test.text","wb")
# print(json.dumps(info)) 使用json只能处理简单的数据类型 列表,字典,字符串 所以无法处理函数只能使用pickle
f.write(pickle.dumps(info))
f.close()

import pickle   # pickle只能序列化Python 其他的不行比如Java 它只认识json

def sayhi(name):
    print("hello2,",name)
f = open("test.text","rb")
data = pickle.loads(f.read())
print(data["func"]("scott"))

  



posted @ 2017-01-09 04:01  onlylc  阅读(115)  评论(0)    收藏  举报