函数对象、函数嵌套、名称空间与作用域、装饰器

 

一 函数对象

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

#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 

 

posted on 2018-06-07 15:25  <Hbw>  阅读(101)  评论(0编辑  收藏  举报