zoukankan      html  css  js  c++  java
  • 函数对象、函数嵌套、名称空间与作用域、装饰器

     

    一 函数对象

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

    #1 可以被引用
    #2 可以当作参数传递
    #3 返回值可以是函数
    #3 可以当作容器类型的元素

    二 利用该特性,优雅的取代多分支的if

    def foo():
        print('foo')
    
    def bar():
        print('bar')
    
    dic={
        'foo':foo,
        'bar':bar,
    }
    while True:
        choice=input('>>: ').strip()
        if choice in dic:
            dic[choice]()

     

    二 函数嵌套

    一 函数的嵌套调用

    def max(x,y):
        return x if x > y else y
    
    def max4(a,b,c,d):
        res1=max(a,b)
        res2=max(res1,c)
        res3=max(res2,d)
        return res3
    print(max4(1,2,3,4))

    二 函数的嵌套定义

    def f1():
        def f2():
            def f3():
                print('from f3')
            f3()
        f2()
    
    f1()
    f3() #报错,为何?请看下一小节

     

    三 名称空间与作用域

    一 什么是名称空间?

    名称空间:存放名字的地方,三种名称空间,(之前遗留的问题x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方)

    二 名称空间的加载顺序

    python test.py
    #1、python解释器先启动,因而首先加载的是:内置名称空间
    #2、执行test.py文件,然后以文件为基础,加载全局名称空间
    #3、在执行文件的过程中如果调用函数,则临时产生局部名称空间

    三 名字的查找顺序

    局部名称空间--->全局名称空间--->内置名称空间
    
    #需要注意的是:在全局无法查看局部的,在局部可以查看全局的,如下示例
    
    # max=1
    def f1():
        # max=2
        def f2():
            # max=3
            print(max)
        f2()
    f1()
    print(max) 

    四 作用域

    #1、作用域即范围
            - 全局范围(内置名称空间与全局名称空间属于该范围):全局存活,全局有效
          - 局部范围(局部名称空间属于该范围):临时存活,局部有效
    #2、作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关,如下
    x=1
    def f1():
        def f2():
            print(x)
        return f2
    x=100
    def f3(func):
        x=2
        func()
    x=10000
    f3(f1())
    
    #3、查看作用域:globals(),locals()
    
    
    LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
    locals 是函数内的名字空间,包括局部变量和形参
    enclosing 外部嵌套函数的名字空间(闭包中常见)
    globals 全局变量,函数定义所在模块的名字空间
    builtins 内置模块的名字空间

     

    闭包函数

    一 什么是闭包?

    # 闭包函数
    # 闭指的是:该函数是一个内部函数
    # 包指的是:指的是该函数包含对外部作用域(非全局作用域)名字的引用
    def outter():
        x = 1
        def inner():
            print(x)
    
        return inner
    
    f=outter()
    
    def f2():
        x=1111111
        f()
    
    f2()
    
    def f3():
        x=4444444444444
        f()
    f3()

    二 闭包的意义与应用

    # 为函数体传值的方式一:使用参数的形式
    def inner(x):
        print(x)
    
    inner(1)
    inner(1)
    inner(1)
    # 为函数体传值的方式二:包给函数
    
    def outter(x):
        # x=1
        def inner():
            print(x)
        return inner
    
    f=outter(1)
    f()
    #闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
    #应用领域:延迟计算(原来我们是传参,现在我们是包起来)
    
    import requests
    
    def outter(url):
        # url='https://www.baidu.com'
        def get():
            response=requests.get(url)
            if response.status_code == 200:
                print(response.text)
        return get
    
    baidu=outter('https://www.baidu.com')
    python=outter('https://www.python.org')
    
    
    baidu()
    baidu()
    
    python()
    python()

     

    装饰器

    装饰器就是闭包函数的一种应用场景

    一 为何要用装饰器

    #开放封闭原则:对修改封闭,对扩展开放

    二 什么是装饰器

    装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
    强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
    装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

    三 装饰器的使用

    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
    def foo():
        time.sleep(3)
        print('from foo')
    foo()

    装饰器语法

    def deco(func):
        def wrapper(*args,**kwargs):  #原被装饰函数为有参函数传参
            
            res=func(*args,**kwargs) #传入参数给原函数用
            
            return res #原被装饰函数有返回值
        return wrapper 
    
    
    #被装饰函数的正上方,单独一行
    @deco1
    @deco2
    @deco3
    def foo():
        pass
    
    foo=deco1(deco2(deco3(foo)))
    #装饰器语法糖
    # 在被装饰对象正上方,并且是单独一行写上@装饰器名
    
    import time
    def timmer(func):
        #func=最原始的index
        def wrapper(*args,**kwargs):
            start=time.time()
            res=func(*args,**kwargs)
            stop=time.time()
            print('run time is %s' %(stop - start))
            return res
        return wrapper
    
    @timmer # index=timmer(index)
    def index():
        print('welcome to index')
        time.sleep(1)
        return 123
    
    @timmer # home=timmer(home)
    def home(name):
        print('welcome %s to home page' %name)
        time.sleep(2)
    
    res=index()
    home('w')

     有参装饰器

    import time
    current_user={'user':None}
    def auth(engine='file'):
        def deco(func):
            def wrapper(*args,**kwargs):
                if current_user['user']:
                    #已经登陆过
                    res = func(*args, **kwargs)
                    return res
                user=input('username>>: ').strip()
                pwd=input('password>>: ').strip()
                if engine == 'file':
                    # 基于文件的认证
                    if user == 'han' and pwd == '123':
                        print('login successful')
                        # 记录用户登陆状态
                        current_user['user']=user
                        res=func(*args,**kwargs)
                        return res
                    else:
                        print('user or password error')
                elif engine == 'mysql':
                    print('基于mysql的认证')
                elif engine == 'ldap':
                    print('基于ldap的认证')
                else:
                    print('无法识别认证来源')
            return wrapper
        return deco
    
    @auth(engine='mysql') # @deco #index=deco(index) #index=wrapper
    def index():
        print('welcome to index page')
        time.sleep(1)
    
    @auth(engine='mysql')
    def home(name):
        print('welecome %s to home page' %name)
        time.sleep(0.5)
    
    
    index()
    home('han')

    匿名函数

    一 什么是匿名函数?

    匿名就是没有名字
    def func(x,y,z=1):
        return x+y+z
    
    匿名
    lambda x,y,z=1:x+y+z #与函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,除非让其有名字
    func=lambda x,y,z=1:x+y+z 
    func(1,2,3)
    #让其有名字就没有意义

    二 有名字的函数与匿名函数的对比

    #有名函数与匿名函数的对比
    有名函数:循环使用,保存了名字,通过名字就可以重复引用函数功能
    
    匿名函数:一次性使用,随时定义
    
    应用:max,min,sorted,map,reduce,filter

    max min map filter sorted 与匿名函数应用

    #max min map filter sorted
    salaries={
        'egon':3000,
        'alex':100000000,
        'wupeiqi':10000,
        'yuanhao':2000
    }
    
    # max的工作原理
    #1 首先将可迭代对象变成迭代器对象
    #2 res=next(可迭代器对象),将res当作参数传给key指定的函数,然后将该函数的返回值当作判断依据
    # def func(k):
    #     return salaries[k]
    #
    # print(max(salaries,key=func)) #next(iter_s)
    #'egon', v1=func('egon')
    #'alex', v2=func('alex')
    #'wupeiqi', v3=func('wupeiqi')
    #'yuanhao', v4=func('yuanhao')
    
    
    
    # salaries={
    #     'egon':3000,
    #     'alex':100000000,
    #     'wupeiqi':10000,
    #     'yuanhao':2000
    # }
    # print(max(salaries,key=lambda k:salaries[k])) #next(iter_s)
    # print(min(salaries,key=lambda k:salaries[k])) #next(iter_s)
    
    
    # l=[10,1,3,-9,22]
    # l1=sorted(l,reverse=False)
    # print(l1)
    
    # l2=sorted(l,reverse=True)
    # print(l2)
    
    # salaries={
    #     'egon':3000,
    #     'alex':100000000,
    #     'wupeiqi':10000,
    #     'yuanhao':2000
    # }
    #
    # print(sorted(salaries,key=lambda k:salaries[k],reverse=True))
    
    names=['张明言','刘华强','苍井空','alex']
    
    # map的工作原理
    #1 首先将可迭代对象变成迭代器对象
    #2 res=next(可迭代器对象),将res当作参数传给第一个参数指定的函数,然后将该函数的返回值当作map的结果之一
    # aaa=map(lambda x:x+"_SB",names)
    # print(aaa)
    # print(list(aaa))
    
    # print([name+"_SB" for name in names])
    
    # filter的工作原理
    #1 首先将可迭代对象变成迭代器对象
    #2 res=next(可迭代器对象),将res当作参数传给第一个参数指定的函数,然后filter会判断函数的返回值的真假,如果为真则留下res
    names=['alexSB','egon','wxxSB','OLDBOYSB']
    
    # print([name for name in names if name.endswith('SB')])
    
    aaa=filter(lambda x:x.endswith('SB'),names)
    print(aaa)
    print(list(aaa))

    内置函数

    #注意:内置函数id()可以返回一个对象的身份,返回值为整数。这个整数通常对应与该对象在内存中的位置,但这与python的具体实现有关,不应该作为对身份的定义,即不够精准,最精准的还是以内存地址为准。is运算符用于比较两个对象的身份,等号比较两个对象的值,内置函数type()则返回一个对象的类型
    
    #更多内置函数:https://docs.python.org/3/library/functions.html?highlight=built#ascii 

  • 相关阅读:
    用JavaScript+CSS实现Mootools竖排动画菜单
    如何对html:select下拉列表里的数据进行排序
    Work with Unicode, CCSID & DBCS
    学习笔记之搜索引擎—原理、技术与系统
    C#中如何创建文件夹
    学习笔记之Effective C++ 2nd Edition
    Global variables vs. Host variables vs. Parameter markers
    【ZZ】cin、cin.get()、cin.getline()、getline()、gets()等函数的用法
    freopen C/C++文件输入输出利器
    [ZZ]用Eclipse开发C/C++程序的图形化配置
  • 原文地址:https://www.cnblogs.com/hanbowen/p/9150807.html
Copyright © 2011-2022 走看看