Dayday up ---- python Day4

装饰器:

  定义: 本质是函数,装饰其它函数,就是为其它函数添加附加功能

  原则: 1、不能修改被装饰的函数的源代码

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

实现装饰器的知识储备:

      1、函数即“变量”,包括匿名函数

      2、高阶函数

       

      3、嵌套函数

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

匿名函数: 没有函数名,如果不用变量引用,内存会被回收

lambda

calc = lambda x:x*3   # lambda标示匿名函数
print(calc(3))             #   调用函数 并且给x赋值

calc1 = lambda y:y/2
print(calc1(4))

 高阶函数:(两种形式)

  1、把一个函数名当作实参传给另一个函数,例如把函数test1传给test2,test2(test1) (在装饰器中可以实现不修改被装饰函数的源代码的情况下为其添加功能)

  2、返回值中包含函数名(在装饰器中可以实现不修改函数的调用方式)

 

import time
def test1():
    "test1"
    time.sleep(1)
    print("in the test1")

def test(func):     # func = test1
    "in the test"
    print("in the test")
    start_time = time.time()   #记录开始时间
    func()      #相当于调用test1()
    stop_time = time.time()    #记录结束时间
    print("the func run time is %s " % (stop_time-start_time))   #计算运行时间

test(test1)    #将test1赋值给func作为位置参数


in the test
in the test1
the func run time is 1.0 

 

嵌套函数:

   函数体内再用def定义函数

def test():
    print("in the test")
    def test1():
        print("in the test1")
    test1()         #在函数体内调用内部函数 

test()     #调用test函数

 

装饰器实例1: 

# -*- coding:utf-8 -*-
import time

def timer(func):    #装饰器
    "decorator"
    def deco(*args,**kwargs):     #嵌套函数,使用return调用 *args,**kwargs
        start_time = time.time()
        func(*args,**kwargs)         #调用func func = test1
        stop_time = time.time()
        print("func run time %s"% (stop_time-start_time))
    return deco         #使用高阶函数中的返回值包含函数名,可以使添加装饰器不修改调用方式 

@timer      # 语法糖 @装饰器名字 相当于 test1 = timer(test1)= deco() = test1() , func = test1() 所以如果test1有参数,deco和func都得写上参数 
def test1():          #原始函数代码
    time.sleep(2)
    print("in the test1")
@timer
def test2(name):
    time.sleep(3)
    print("my name is %s" % name)

# test1=timer(test1)   #timer(test1)需要返回值的内存地址, 然后bar()输出结果 
test1()
test2("ll")

添加页面验证装饰器:

# --*--coding:utf-8--*--
user,passwd = "ll","123"
def auth(auth_type):
    def wapper(func):
        def deco(*args,**kwargs):
            # print("func args:",*args,**kwargs)
            if auth_type == "local":
                print("auth_func: %s" % auth_type)
                username = input("\033[38mplease input your username:\033[0m")
                password = input("\033[38mplease input your password:\033[0m")
                if username == user and password == passwd:
                    print("验证成功")
                    funct = func(*args,**kwargs)
                    print("--------------")
                    return funct
                else:
                    exit("验证失败")
            elif auth_type == "ldap":
                print("auth_func: %s" % auth_type)
                print("ldap authtication")
        return deco
    return wapper
#源代码
def index():
    print("\033[35min the index\033[0m")

@auth(auth_type = "local")     # 验证方式为local
def home(name):
    print("\033[34min the home,welcome %s\033[0m" % name)
    return "home html"

@auth(auth_type = "ldap")      #验证方式为ldap
def bbs():
    print("\033[36min the bbs\033[0m")


index()
print(home("yy"))
bbs()

 

列表生成式:  

举例:以前我们生成一个1~10的列表是这样的

list = []
for i in range(10):
    list.append(i)

print(list)

 列表生成式使代码更简洁

list = [i for i in range(10)]
print(list)

 

生成器 

列表生成式在定义list变量的时候,结果已经出来了,而生成器先预留一块内存空间,只有在调用的时候才生成相应的数据

 生成器取数据:

只有一个__next__()方法  ,2.7里面是 next()

list = ( i for i in range(10))
print(list)
print(list.__next__())
print(list.__next__())
print(list.__next__())   #生成器取数据的方法

 斐波那契数:

def fib(max):       # 定义参数
    n,a,b =  0,0,1
    while n < max:
        print(b)
        a,b = b,a+b    # 根据规律写表达式
        n +=1           #计数器

fib(10)

用生成器生成:

要把fib函数变成generator,只需要把print(b)改为yield b就可以了:  

def fib(max):
    n,a,b = 0,0,1
    while n < max:
        yield b              #返回并记录当前值
        a,b = b,a+b
        n +=1
    return "done"

a = fib(10)
print(a)
while True:
    try:                   #异常处理,如果不出错则执行
        x = next(a)
        print(x)
    except StopIteration as e:  #如果出错执行
        print('Generator return value:', e.value)
        break

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

还可通过yield实现在单线程的情况下实现并发运算的效果

import time
def consumer(name):
    print("%s 准备吃包子啦!" %name)
    while True:
       baozi = yield

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

# c = consumer("lyx")
# c.__next__()
# c.send("haha")

#单线程并行 也叫做 协程

def producer(name):
    c = consumer('A')
    c2 = consumer('B')
    c.__next__()
    c2.__next__()
    print("%s 开始准备做包子啦!"% name)
    for i in range(10):
        time.sleep(1)
        print("做了1个包子,分两半!")
        c.send(i)
        c2.send(i)

producer("ll")

迭代器: 

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

  一类是集合数据类型,如listtupledictsetstr等;

  一类是generator,包括生成器和带yield的generator function。

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

  生成器一定是迭代器,但迭代器不一定是生成器

可以使用isinstance()判断一个对象是否是Iterable对象:

from collections import Iterable
print(isinstance([], Iterable))   ---True
print(isinstance("ninhao", Iterable))   ---True
print(isinstance(100, Iterable))   ---False

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

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

生成器都是Iterator对象,list、dict、str虽然是Iterable,却不是Iterator。

#判断是不是迭代器
from collections import Iterator
print(isinstance([], Iterator))    ---False

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

from collections import Iterator
print(isinstance(iter([]), Iterator))   # iter将可迭代对象转换为迭代器 

 

为什么listdictstr等数据类型不是Iterator

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

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

小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

range(10) python3里就是一个迭代器,python2 不是,是一个列表

循环文件for i in f 也是迭代器

for x in [1,2,3,4,5,6]:
    print(x)
# 等于 
it = iter([1, 2, 3, 4, 5])
while True:
    try:
        x = next(it)
        print(x)
    except StopIteration:
        break


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

 

json 序列化 

 

json是所有语言里面都通用的,和其它语言进行交互

序列化:内存里面有一个数据结构,你希望将它保存下来,重用,或者发送给其他人。 很多游戏允许你在退出的时候保存进度,然后你再次启动的时候回到上次退出的地方。(实际上, 很多非游戏程序也会这么干。) 在这个情况下, 一个捕获了当前进度的数据结构需要在你退出的时候保存到磁盘上,接着在你重新启动的时候从磁盘上加载进来。这个数据只会被创建它的程序使用,不会发送到网 络上,也不会被其它程序读取。因此,互操作的问题被限制在保证新版本的程序能够读取以前版本的程序创建的数据。

json使用:

# json 序列化 
import json
info = {
    "name": "ll",
    "age": "22"
}

#用json把字典序列化到文件
with open("json.txt","w") as f:
    f.write(json.dumps(info))
    #或者,两种方式都可行
    json.dump(info,f)

 

#json 反序列化
import json

#把文件反序列化
with open("json.txt","r") as f:
    data = json.loads(f.read())
    print(data['age'])
    #或者,两种方式都可行
    data = json.load(f)
    print(data)

 但json只支持简单的字典,列表等数据类型,不能处理复杂的类似函数这样的

 

还有一种序列化的方式

pickle 序列化

pickle 和json的用法一样,可以处理复杂的数据类型,比如函数,但只能在python本语言使用

pickle写入文件的是python可以识别的,看起来像乱码,其实不是乱码

类似:

# -*- coding:utf-8 -*-
# pickle 序列化 
import pickle


def sayhi(name):
    print("hello,", name)


info = {
    "name": "ll",
    "age": "22",
    "func": sayhi
}

# 用picle把字典以及函数序列化到文件
with open("pickle.txt", "wb") as f:   #需要用二进制格式写入 
    #f.write(pickle.dumps(info))
    # 或者,两种方式都可行
    pickle.dump(info, f)

 

# -*- coding:utf-8 -*-
#pickle 反序列化
import pickle
def sayhi(name):   #需要把函数在反序列化文件里写上,函数名相同即可
    print("hello,", name)
#把文件反序列化
with open("pickle.txt","rb") as f:     #需要二进制读取 
    # data = pickle.loads(f.read())
    # print(data['age'])
    #或者,两种方式都可行
    data = pickle.load(f)
    print(data['func']('ll'))    #调用函数并且传值 

 

建议: 最好一次dump一次load,虽然可以dump多次,但是只能load一次

 

python项目中文件调用其它目录文件

import os,sys
BASE_DIR = os.path.dirname( os.path.dirname( os.path.abspath(__file__) ) )
    #__file__ 返回文件的相对路径
sys.path.append(BASE_DIR)
from conf import shopping    #从上级目录conf导入shopping文件 

shopping.deco()   #调用文件的函数 

 

posted @ 2016-08-19 07:16  a_monologue  阅读(91)  评论(0)    收藏  举报