• Long Way To Go 之 Python 4


    装饰器(decorator)

          (“器”代表的是函数)

    定义本质是函数

    组成:高阶函数+嵌套函数 --> 装饰器

    作用:用来装饰其他函数  in other words,为其他函数添加附加功能

            (eg. 假如程序已上线,如果想新增功能,但是又不能改源代码)

    原则:

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

            2.不能修改被装饰的函数的调用方试

     

    Q:  高阶嵌套函数是个什么鬼???

    高阶函数:

          1.把一个函数当做实参传给另一个函数(在不修改被装饰函数源代码的情况下为其添加功能)        

    import time
    def bar():
        time.sleep(3)
        print("in the bar")
    
    def test1(func):
        start_time = time.time()
        func()   # run bar()
        stop_time = time.time()
        print("the func run time is %s"%(stop_time -start_time))   # 统计的是bar的运行时间
    
    test1(bar) # func = bar 所以可以进行func()      传的内存地址
    test1(bar())   # 把bar()的返回值传进去了        传的返回值
    # BUT !调用方式变了,不是装饰器
    View Code

          2.返回值中包含函数名(不修改函数的调用方式)

    import time
    def bar():
        time.sleep(3)
        print("in the bar")
    
    def test2(func):
        print(func) # 打印func的内存地址,也就是bar的内存地址
        return func # return bar的内存地址
    
    bar = test2(bar)
    bar() # run bar
    View Code

    嵌套函数:

            在一个函数的函数体内用def去申明另一个函数

    #嵌套函数
    def foo():
        print("in the foo")
        def bar():    # 相当于局部变量,所以不能在外面直接调用bar(),所以要写在里面
            print("in the bar")
        bar()
    foo()
    
    
    # 这个不是函数的嵌套,这叫函数的调用
    def test1():
        test2()
    test1()
    View Code

    EXAMPLE 1

    优化(@timmer)

    def timer(func): #timer(test1)   把test1的内存地址传给func,func = test1
        def deco():
            start_time = time.time()
            func()      # run test1
            stop_time = time.time()
            print("the func run time is %s"%(start_time-stop_time))
        return deco   # 返回这个函数的内存地址
    
    @timer   # 这就相当于  test1 = timer(test1)
    def test1():
        time.sleep(3)
        print("in the test1")
    
    @timer
    def test2():
        time.sleep(3)
        print("in the test2")
    
    test1()  
    test2()  # 其实调用的是deco这个函数,因为timer(test1)的返回值是deco的内存地址
    View Code

    优化(调用时传入多个参数)

    def timer(func): #timer(test1)   把test1的内存地址传给func,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"%(start_time-stop_time))
        return deco   # 返回这个函数的内存地址
    
    @timer   # 这就相当于  test1 = timer(test1) = deco
    def test1():
        time.sleep(1)
        print("in the test1")
    
    @timer   # test2 = timer(test2)   =  deco
    # test2() = deco()     所以在deco里加args
    def test2(name,age):
        print("test2:",name,age,)
    
    test1()
    test2("alex",22)
    View Code

    EXAMPLE 2 !!

    import time
    
    user,passwd = "alex","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("33[32;1mUser has passed authenfication33[0m")
                       res = func(*args,**kwargs) # return from home
                       print("------after authenficaiton")
                       return res
                    else:
                       exit("33[31;1mInvalid username or password33[0m")
                 elif auth_type == "ladp":
                       print("毛线ldap,不会------")
            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 "from home"
    
    
    @auth(auth_type = "ldap")   # 远程认证
    def bbs(): # 论坛
        print("welcome to bbs page")
    
    index()
    print(home())   # return None  如果没有return func()的话
    bbs()
    View Code

    ps:

    函数及变量

    # 没问题
    def bar():
        print("in the bar")
    def foo():
        print("in the foo")
        bar()
    
    foo()
    
    
    
    # bar定义到下面也是可以运行的
    def foo():
        print("in the foo")
        bar()
    def bar():
        print("in the bar")
    
    foo()
    
    
    
    # 会报错,因为函数和变量一样,是先定义,在调用。所以会报错
    def foo():
        print("in the foo")
        bar()
    
    foo()
    def bar():
        print("in the bar")
    View Code

     

    生成器(generator)

        原理:只有在调用时才会生成相应的数据(假如一个大数据,只循坏了前5次,那么后面的数据是没有准备好的)

        作用:省内存

        特点:生成器只记住当前位置(不管前后),不能后退回返,也不能跳着走

        方法:只有一个next方法,  __next__()

    #生成器
    #数据规律的情况下
    >>>print(i*2 for i in range(10))
    <generator object <genexpr> at 0x0000000001E00E60>
    
    #数据不规律
    #fibonacci
    >>>def fib(max):
           n,a,b = 0,0,1
           while n < max:
               yield b   #  用yield就是生成器了,用来保留函数中断的状态
               a,b = b,a+b   # 每次向右移一个数
               n = n+1
           return "----done---"
    
    >>>print(fib(10))
    <generator object fib at 0x0000000002180E60>

    next方法的使用

    f = fib(10)
    
    # 用next方法,一个一个数字的打印
    print(f.__next__())
    print(f.__next__())
    print(f.__next__())
    
    
    # 用for循环就不会打印done
    for i in f:
         print(i)
    
    
    # 如果出现异常,比如只有10个数据,但是取了11次
    while True:
        try:
            x = next(f)
            print("f:",x)
        except StopIteration as e:
            print("Generator return value:",e.value) # e.value = ----done----
            break

    EXAMPLE

    生成器并行

    import time
    def consumer(name):
        print("%s 准备吃包子啦!"%name)
        while True:
            baozi = yield  # yield作用是保存当前状态,然后返回
    
            print("包子[%s]来了,被[%s]吃了!"%(baozi,name))
    
    #c = consumer("chenronghua")
    #c.__next__()   #xxx 准备吃包子啦!
    #c.__next__()  # next只是调用yield,但是不传值,所以包子出来的是none
    
    #b1 = "韭菜馅"
    #c.send(b1)   # send 不仅调用,还可以给yield传值
    #c.__next__()  # 这里又传值了,所以出来的是none
    
    def producer(name):
        c = consumer("A") # 如果只写这一行,不写next,相当于只是把函数变成生成器,而使用next之后,才能执行到baozi = yield
        c2 = consumer("B")
        c.__next__()
        c2.__next__()
        print("老子开始准备做包子啦!")
        for i in range(2):
            time.sleep(1)
            print("做了1个包,分两半!")
            c.send(i)
            c2.send(i)
    producer("alex")
    View Code

    ps:

    列表生成式

    >>>print([i*2 for i in range(10)])
    [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
    >>>
    >>>[func(i) for i in range(10)] # 传函数也可以

    迭代器(Iterator)

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

                没有next方法,就不叫迭代器,有next方法,就是~

       作用:

             可以表示一个无限大的数据流(eg.全体自然数),而list是无法存储无穷尽的数

             我们不知道它的长度,只能不断用next()函数计算下一个数据,所以说,Iterator是惰性的,只有需要返回下一个数据的时候它才会计算        

       

       补充:  

              1. 可直接作用于for循环的数据类型

                   a)  集合数据类型:

                         list, tuple, dict, set,str...

                   b)  生成器:

                         生成器和带yield的generator function

               2. 可迭代对象(Iterable)

                    可以直接用于for循环的对象叫“可迭代对象”

                   (eg. a = [1,2,3], 是Iterable,但不是Iterator,因为没有next调用)

        总结:

              -----  !!!迭代器不一定是生成器,但生成器肯定是一个迭代器!!!

              -----  可作用于for循坏的对象都是Iterable

                       可作用于next()函数的对象都是Iterator对象

              -----  list,dict,str...虽然是Ierable,却不是Iterator

                       但可以用 iter() 函数来得到一个Iterator

              ----- isinstance()

    # 判断对象是否是一个可迭代对象或者迭代器
    >>>from collections import Iterable,Iterator
    >>>isinstance([], Iterable)
    True
    >>>isinstance((), Iterable)
    True
    >>>isinstance("abc", Iterable)
    True
    >>>isinstance(100, Iterable)
    False
    >>>isinstance((x for x in range(10)), Iterable)
    True
    
    >>>isinstance((x for x in range(10)) ,Iterator)
    True

    Q:为什么list, dict, str ... 数据类型不是Iterator?

         因为python的Iterator对象表示的是一个数据流,Iterator对象可被next()函数调用并不断返回下一个数据(戳一下,动一下),直到没有数据取出并抛出StopIteration 错误

    软件目录开发规范

    不同目录间进行模块调用

    自定义模块

    # 目录假设:Atm-->bin, core--->atm, main
    
    import os
    import sys
    
    #print(__file__) # 当前相对路径,看起来是绝对路径,只是因为是在pycharm里,在cmd里就是相对路径
    print(os.path.abspath(__file__))  # 绝对路径
    print(os.path.dirname(os.path.abspath(__file__)))  # 返回目录名,不要文件名
    
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    print(BASE_DIR)
    
    sys.path.append(BASE_DIR) # 添加坏境变量
    
    # 导入模块
    from conf import settings
    from core import main
    
    # run main里的login()函数
    main.login()
    C:/Users/apple/PycharmProjects/s14/day4/Atm/bin/atm.py
    C:UsersapplePycharmProjectss14day4Atminatm.py
    C:UsersapplePycharmProjectss14day4Atmin
    C:UsersapplePycharmProjectss14day4Atm


        

        

  • 相关阅读:
    __proto__、prototype、constructor 之间的关系
    call()与apply()区别
    条件注释判断浏览器
    永远在页面底部的层
    jQuery1.9和jQuery2.0加载(IE10下条件判断失效)
    mousewheel
    2013多校第四场 G题 ZZ的搬砖难题
    hdu 4389 x mod f(x) 数位DP
    hdu 4468 spy 构造kmp
    hdu 4466 triangle 三角形统计 数学计数
  • 原文地址:https://www.cnblogs.com/momo-momo-jia/p/6848801.html
Copyright © 2020-2023  润新知