• python自动化开发-[第四天]-函数


    今日概要:

      - 函数对象

      - 函数嵌套

      - 命名空间和作用域

      - 闭包

      - 装饰器

      - 迭代器

      - 生成器

      - 内置函数

    一、函数对象

      1、函数对象的定义:

        函数是第一类对象,即函数可以当作数据传递

        可以被引用,可以被当作参数传递,可以当返回值,可以当做容器类型的元素

    #1 可以被引用
    def foo():
        print('from foo')
    
    func=foo
    print(foo)  #函数对象
    print(func)
    func() #执行函数
    #2 可以当做参数传递
    def foo():
        print('from foo')
    
    def bar(func):
        print(func)
        func()
    
    bar(foo)
    #3 可以当返回值
    def foo():
        print('from foo')
    
    def bar(func):
        return func
    
    f=bar(foo)
    
    print(f)
    
    f()
    #4 可以做容器类型元素
    def foo():
        print('from foo')
    dic={'func':foo}
    
    print(dic['func'])
    
    dic['func']()
    

      

     

      2、应用

    def select():
        print ('---select')
    
    def update():
        print ('----update')
    
    dic_list = {'select':select,
                'update':update
                }
    
    def main():
        while True:
            sql = input('-->')
            if not sql : continue
    
            l = sql.split(' ')
            cmd = l[0]
            if cmd in dic_list:
                dic_list[cmd]()  #直接通过函数名称加()进行执行
    
    main()  

         3、函数传可以传参数加默认形参数据类型 例子:backup: int 

    def test(sql,backup: int): #默认是backup是int类型,可以修改
        print(type(sql))
        print(type(backup))
        print(sql,backup)
    
    if __name__ == '__main__':
        test("select * from t1",123)
    
    
    """
    <class 'str'>
    <class 'int'>
    select * from t1 123
    
    """
    

      


    二、函数嵌套

      1、函数的嵌套调用

    #用嵌套函数求最大值
    def max4(a,b,c,d):
        res1=max(a,b)
        res2=max(res1,c)
        res3=max(res2,d)
        return res3
    
    print(max4(10,99,31,22))
    

        

      2、函数的嵌套定义

    def f1():
    
        def f2():
            print('from f2')
            def f3():
                print('from f3')
            f3()
        f2()
    
    
    # f1()  #不允许在最外层调用最里层的函数
    # f3()  #会报错
    

      

      

    三、命名空间和作用域

      1、命名空间

          名字的定义import time,  x='dragon',def black():,class black 这四类都是在定义名字

      2、三种名称空间

        内置名称空间(python解释器启动时会产生)

        print(sum)

        print(max)

    #查看内置函数列表
    import builtins
    for i in dir(builtins):
        print(i) 

      3、全局名称空间

        文件的执行会产生全局名称空间,指的是文件级别定义的名字都会放到该空间

    x=1
    
    def func():
        money=2000
        x=2
        print('func')
    print(x) # x = 1
    print(func)
    func()
    print(money) #不是全局命名空间不能输出
    
    func()
    print(x) 

       4、局部命名空间

        调用函数时会产生局部命名空间,只在函数调用时临时绑定,调用结束后解绑定

     

    x=10000
    def func():
        x=1
        def f1():
            print (x)
        f1()
    func()
    

     

      5、作用域

        作用域分为全局作用域和局部作用域

        全局作用域:内置命名空间,全局命名空间

        局部作用域:局部作用空间

      6、作用域名字都查找顺序

        局部名称空间-->全局名称空间-->内置名称空间

      7、查看全局作用域和局部作用域的方法

        

    #查看全局作用域内的名字:
    print(gloabls())
    #查看局局作用域内的名字:
    print(locals())
    x=1000
    def func(y):
        x=2
        print(locals())
        print(globals())  #局部比全局多一个x=2
    
    func(1)
    

      

       8、总结:

       全局作用域:全局有效,在任何位置都能被访问到,除非del删掉,否则会一直存活到文件执行完毕

       局部作用域的名字:局部有效,只能在局部范围调用,只在函数调用时才有效,调用结束就失效

    四、闭包

      1、闭包的定义

        定义在内部函数,包含对外部作用域而非全局作用域的引用,该内部函数称为闭包函数

    例子:

    def f1():
        x = 1
        def f2():
            print(x)
    
        return f2
    
    f=f1()
    print(f)  

       2、应用,惰性计算

    def f1():
    
        x = 1
    
        def f2():
            print (x)
    
        return f2
    
    f = f1()
    
    f() 

       3、

      

    #__closure__方法,查看闭包函数下有多少个参数
    
    
    #查看每个参数对应的值
    oldboy.__closure__[0].cell_contents

     

    x=1
    # y=2
    def f1():
        # x=1
        y=2
        def f2():
            print(x,y)
        return f2
    
    f=f1()
    print(f.__closure__[0].cell_contents) 

    五、装饰器

      1、装饰器的定义:装饰器是修饰别人的工具,工具指是函数,装饰器本身可以是任何可调用对象,被装饰的对象也可以是任意可调用对象

      2、用装饰器的原因:

      开放封闭原则:对修改是封闭的,对扩展是开放的
      装饰器就是为了在不修改被装饰对象的源代码以及调用方式的前提下,为其添加新功能

      3、无参装饰器,@为python的语法糖,装饰器遵循闭包规则  

    import time
    
    def timmer(func):
        def wrapper():
            start_time=time.time()
            func() #index()
            stop_time=time.time()
            print('run time is %s' %(stop_time-start_time))
        return wrapper
    
    
    @timmer #index=timmer(index)
    def index():
        time.sleep(3)
        print('welcome to index')
    
    
    f=timmer(index)  
    print(f)
    f() #wrapper()---->index()
    
    index=timmer(index) #index==wrapper
    
    index() #wrapper()----->

       4、有参装饰器

    import time
    def timmer(func):
        def wrapper(*args,**kwargs):
            start_time=time.time()
            res=func(*args,**kwargs)
            stop_time=time.time()
            print('run time is %s' %(stop_time-start_time))
            return res
        return wrapper
    
    @timmer #index=timmer(index)
    def index():
        time.sleep(3)
        print('welcome to index')
        return 1
    
    @timmer
    def foo(name):
        time.sleep(1)
        print('from foo')
    
    
    res=index() #wrapper()
    print(res)
    
    res1=foo('dragon')  #res1=wrapper('egon')
    print(res1)

       5、应用

    #用装饰器写用户登录,装饰器带参数传入
    user_info = {'user':None,'user_status':False}
    
    def auth(driver = 'file'):
        def auth1(func):
    
            def wrapper(*args,**kwargs):
                if driver == 'file':
                    if user_info['user'] and user_info['user_status']:
                            res = func(*args,**kwargs)
                            return  res
                    else:
    
                        user_input = input('请输入帐号:')
                        user_pass = input('请输入密码:')
                        if user_input == 'alex' and user_pass == '123':
                            user_info['user'] = 'alex'
                            user_info['user_status'] = True
                            res = func(*args,**kwargs)
                            print ('login successfully')
                            return  res
                        else:
                            print ('login error')
                elif driver == 'mysql':
                    print ('------>mysql')
    
            return wrapper
        return  auth1
    
    
    @auth('file') #auth1 == index = auth1(index) == index = wrapper
    def index ():
        print ('welcome login index')
    @auth('mysql')
    def home(name):
        print ('%s welcome login home page' %(name))
    
    index()
    
    home('alex')   

      6、多个装饰器的优先级

      @timmer

      @auth

      装饰器会优先执行最上面的,然后在执行以此类推,在定义节点从下往上定义,在执行阶段从上往下执行

    应用

    import time
    def timmer(func):
        def wrapper(*args,**kwargs):
            print('====>timmer.wrapper')
            start_time=time.time()
            res=func(*args,**kwargs) #auth_wrapper
            stop_time=time.time()
            print('run time is %s' %(stop_time-start_time))
            return res
        return wrapper
    
    login_user={'user':None,'status':False}
    def auth(driver='file'):
        def auth2(func):
            def wrapper(*args,**kwargs):
                print('=======>auth.wrapper')
                time.sleep(5)
                if driver == 'file':
                    if login_user['user'] and login_user['status']:
                        res=func(*args,**kwargs)
                        return res
                    else:
                        name=input('>>: ')
                        password=input('>>: ')
                        if name == 'egon' and password == '123':
                            login_user['user']='egon'
                            login_user['status']=True
                            print('33[45mlogin successful33[0m')
                            res=func(*args,**kwargs)
                            return res
                        else:
                            print('33[45mlogin err33[0m')
                elif driver == 'ldap':
                    print('==========ldap的认证')
                elif driver == 'mysql':
                    print('==========mysql的认证')
                    return func(*args,**kwargs)
                else:
                    print('=========未知的认证来源')
            return wrapper
        return auth2
    @auth('file')  #index = auth2(time_warpper) --> auth2_warpper(time_warpper)
    @timmer   #index = timmer(index) ---> index = timmer_warpper
    def index():
        time.sleep(3)
        print('welcome to index page')
    
    
    @auth(driver='mysql')
    def home(name):
        print('%s welcome to home page' % name)
    
    
    index()  # auth2_warpper
    

      

      7、functools模块

      在装饰器的wrapper函数上@functools.wraps(func),用python自带的装饰器进行装饰,能将文档信息保留,而不调用装饰器的文档信息

    def deco_1(func):
        print ("enter into deco_1")
        def wrapper(a,b):
            print ("enter into deco_1_wrapper")
            func(a,b)   #传入的是deco_2的wrapper
            print ("over deco_1")
        return wrapper
    def deco_2(func):
        print ("enter  into  deco_2")
        def wrapper(a,b):
            print ("enter into deco_2_wrapper")
            func(a,b)
            print ("over deco_2")
        return wrapper
    
    @deco_2  #addFunc = deco_2的wrapper
    @deco_1  #addFunc = deco_1(addFunc())  ==  addFunc = deco_1(deco_2的wrapper)
    def addFunc(a,b):
        print ("result is %d" %(a+b))
    addFunc(3,4) # addFunc = deco_1(deco_2的wrapper)
    
    
    '''
    输出:
    enter into deco_1
    enter  into  deco_2
    enter into deco_2_wrapper
    enter into deco_1_wrapper
    result is 7
    over deco_1
    over deco_2
    
    '''
    多个装饰器的执行顺序

    六、迭代器

      1、基本概念

        重复+上一次迭代的结果为下一次迭代的初始值,重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值

    #这不是迭代器,只满足重复,未满足上一次迭代的结果为下一次迭代的初始值
    while True:
        print('hello world')
    

       

    #如下为迭代器,重复,上一次的迭代结果为下一次的迭代的初始值
    l = [1, 2, 3]
    count = 0
    while count < len(l):  
        print('====>', l[count])
        count += 1
    
    l = (1, 2, 3)
    count = 0
    while count < len(l):  
        print('====>', l[count])
        count += 1
    
    s='hello'
    count = 0
    while count < len(s):
        print('====>', s[count])
        count += 1
    

       

      2、迭代器的用途

      对于没有索引的数据类型,必须提供一种不依赖索引的迭代方式

      可迭代对象:含内置__iter__方法的都是可迭代对象

      

    [1,2].__iter__()  #列表
    'hello'.__iter__() #字符串
    (1,2).__iter__() #元组
    {'a':1,'b':2}.__iter__() #字典
    {1,2,3}.__iter__() #集合
    

        

      迭代器:执行__iter__方法,得到的结果就是迭代器,迭代器对象有__next__方法

    i=['a','b','c'].__iter__()  #从可迭代对象,变成迭代器
    
    print(i)
    
    print(i.__next__())
    print(i.__next__())
    print(i.__next__())
    print(i.__next__()) #抛出异常:StopIteration  

      字典迭代的是key,可以通过dic[key]获取values

    dic={'a':1,'b':2,'c':3}
    i=dic.__iter__()
    while True:
        try:
            key=i.__next__()
            print(dic[key])
        except StopIteration:
            break  

      __iter__方法 == iter(),__next__方法 == next()

      3、判断一个对象是否为可迭代对象,而不是迭代器对象:

    from collections import Iterable,Iterator
    
    'abc'.__iter__()
    ().__iter__()
    [].__iter__()
    {'a':1}.__iter__()
    {1,2}.__iter__()
    
    f=open('a.txt','w')
    f.__iter__()
    
    
    #下列数据类型都是可迭代的对象
    print(isinstance('abc',Iterable))
    print(isinstance([],Iterable))
    print(isinstance((),Iterable))
    print(isinstance({'a':1},Iterable))
    print(isinstance({1,2},Iterable))
    print(isinstance(f,Iterable))
    
    
    --
    result
    True
    True
    True
    True
    True
    True
    #只有文件是迭代器对象
    # print(isinstance('abc',Iterator))
    # print(isinstance([],Iterator))
    # print(isinstance((),Iterator))
    # print(isinstance({'a':1},Iterator))
    # print(isinstance({1,2},Iterator))
    # print(isinstance(f,Iterator))
    
    --
    result
    False
    False
    False
    False
    False
    True  

      4、总结:

        可迭代对象,只有__iter__方法,执行该方法得到迭代器

      迭代协议:

        对象有__next__方法

        对象有__iter__方法,对于迭代器对象来说,执行__iter__方法,得到的结果仍然是他本身

    dic={'name':'dragon','age':18,'height':'180'}
    print(dic.items())
    i=iter(dic)
    while True:
        try:
            k=next(i)
            print(k)
        except StopIteration:
            break
    

      5、迭代器的优缺点:

      优点:

        1、提供了一种不依赖下标的迭代方式

        2、就迭代器本身来说,更节省内存

      缺点:

        1、无法获取迭代器对象的长度

        2、不如序列类型取值灵活,只是一次性的,只能往后取值,不能往前退

    #enumerate是迭代器
    l=[10000,2,3,4,5]
    
    i=enumerate(l)  
    
    print(next(i))
    print(next(i))
    

      

    七、生成器(yield)

       1、定义

        只要函数体包含yield的关键字,该函数就是生成器函数

        生成器就是迭代器

    例子:

      

    #生成器,只要函数体含yield关键字,该函数就是生成器函数
    
    def res():
        print ('a')
        yield 1
        print ('b')
        yield 2
        print ('c')
        yield 3
        print ('d')
    
    g = res()
    
    for i in g:
        print (i)
    

      2、yield功能

        1、相当于封装好的__iter__和__next__

        2、return只能返回一次值就终止,而yield能返回多值,每次都会将函数暂停,下一次next会从上一次暂停的位置继续执行

    例子:tail -f access.log | grep 'python'

    import time
    def tail(filepath):
        with open(filepath,encoding='utf-8') as f:
            f.seek(0,2)
            while True:
                line=f.readline().strip()
                if line:
                    yield line
                else:
                    time.sleep(0.2)
    
    def grep(pattern,lines):
        for line in lines:
            if pattern in line:
                yield line
    
    
    g=grep('python',tail('a.txt'))  #在grep里添加yield又变成一个生成器,需要g=grep进行调用生成器
    print(g)
    
    for i in g: #for 循环 触发grep生成器执行,grep 生成器会触发for循环,触发上一个tail生成器的执行
        print(i)
    

      

    八、内置函数

      

    abs 求绝对值
    
    all(),括号内放可迭代对象, bool值运算,所有为true才为true,可迭代值为空也为true
    
    any() bool值运算,有一个为真则为真,可迭代对象为空返回false
    
    bin() 把10进制转二进制
    
    hex()
    
    #判断是否为可调用对象
    callable()
    #按照ascii码,将字符对应位置
    chr(68)
    ord
    #complex 复数
    complex(1+2j)
    print (res.real)
    print (res.imag)
    
    #工厂函数
    
    list
    str
    dict
    set 
    int
    
    #dir 查看一个对象的属性
    l = []
    print (l)
    
    #divmod 可以完成分页功能
    
    print (divmod(10,3))
    
    #eval  将字符串转
    dic = {'a':1,'b':2}
    d = eval(dict)
    print (type(d),d['a'])
    #frozenset({1,2})  定义不可变集合
    
    #hash 得到哈希值
    print (hash('adadsd'))
    
    #id is 身份运算符
    
    
    #pow x**y %z
    
    reversed #反转 为迭代器
    
    round #保留几位小数
    
    slice 切片 可以重复利用
    
    lis = ['a','b','c']
    print (lis[1:3:2])
    
    l = slice(1,4,2)
    print (l[s])  #切片方式可以在任意位置去调用
    
    
    vars() 不加参数和locals()
    
    zip #拉链函数
    
    
    
    s = hello
    lis = [1,2,3,4,5]
    
    z = zip(s,lis)
    
    
    __import__
    
    __import__('time')
    #以字符串的形式倒入模块
    

      

      

       

         

      

  • 相关阅读:
    【每天一道PAT】1001 A+B Format
    C++ STL总结
    开篇
    happen-before原则
    java多线程的状态转换以及基本操作
    集合初始容量
    fail-fast机制
    Stack
    Iterator
    Vector
  • 原文地址:https://www.cnblogs.com/liujiliang/p/6892267.html
Copyright © 2020-2023  润新知