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

阅读目录

  1.函数对象

  2.函数嵌套

  3.名称空间与作用域

  4.闭包函数

  5.装饰器

  6.练习

一、函数对象

  一、函数是第一类对象:指的是函数可以当做数据传递。

1.可以被引用
2.可当做函数的参数传入
3.可以当做函数的返回值
4.可以当做容器类型的元素
#详细的使用过程
#1、可以被引用 x=1,y=x
# def func(x,y):
#     print(x,y)
#
# f=func
# f(1,2)
#2、可当做函数的参数传入
# def foo():
# print('from foo')
#
# def bar(func): #func=foo
# # print(func)
# func() #func=foo() func其实就是一个变量名,加上括号就是变量值
#
# bar(foo) #执行过程调用foo
 
#3、可以当做函数的返回值 
#
def foo():
#
  print('from foo')
#
def bar():
#
  return foo #bar 的执行结果就是返回foo函数体 第二步

# f=bar() #找到bar 的执行结果 第一步

# f()

#4、可以当做容器类型的元素
# def foo():
# print('from foo')
#
# def bar():
# return foo
#
# l=[foo,bar] # 得到的结果是列表l=[<function foo at 0x00000000037EE0D0>, <function bar at 0x00000000037EE158>]python的内存地址信息。
# print(l)
# l[0]() #使用列表的方式取数,用0 取出foo 的结果
# def get(): 
#  
print('get')
#
def put():
#
  print('put')
#
def ls():
#
  print('ls')
#
cmd=input('>>: ').strip()
#
if cmd == 'get':
#
  get()
#
elif cmd == 'put':
#
  put()
#
elif cmd == 'ls':
#
  ls()

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

def get():
    print('get')

def put():
    print('put')

def ls():
    print('ls')

def auth():
    print('auth')

func_dic={
    'get':get,
    'put':put,
    'ls':ls,
    'auth':auth
}

# func_dic['put']()
cmd = input('>>: ').strip()
if cmd in func_dic:
    func_dic[cmd]()

二、函数嵌套

  一、函数的嵌套调用

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():
        print('from f2')
        def f3():
            print('from f3')
        f3()
    f2()
f1()

三、名称空间与作用域

  一、什么是名称空间

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

  二、名称空间的执行顺序

python test.py
#1、python解释器先启动,因而首先加载的是:内置名称空间
#2、执行test.py文件,然后以文件为基础,加载全局名称空间
#3、在执行文件的过程中如果调用函数,则临时产生局部名称空间
#内置名称空间(python解释器启动就有):python解释器内置的名字,max,len,print
#全局名称空间(执行python文件时生效):文件级别定义的名字
# x=1
# def func():pass
# import time
# if x == 1:
#     y=2

#局部名称空间(函数调用时生效,调用结束失效):函数内部定义的名字
# func()

#加载顺序:内置---》全局----》局部名称空间
#访问名字的顺序:局部名称空间===》全局----》内置
# x=1
# print(x)

# print(max)

# max=2
# def func():
#     # max=1
#     print(max)
#
# func()


# x='gobal'
# def f1():
#     # x=1
#     def f2():
#        # x=2
#        def f3():
#            # x=3
#            print(x)
#        f3()
#     f2()
#
# f1()
名称空间详解

  三、名称的查找顺序

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

#需要注意的是:在全局无法查看局部的,在局部可以查看全局的,如下示例

# 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 内置模块的名字空间

  五、global与nonlocal关键字

global

global关键字用来在函数或其他局部作用域中使用全局变量。但是如果不修改全局变量也可以不使用global关键字。
gcount = 0

def global_test():
    print (gcount)
    
def global_counter():
    global gcount
    gcount +=1
    return gcount
    
def global_counter_test():
    print(global_counter())
    print(global_counter())
    print(global_counter())

 

二 nonlocal

nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量。


def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter
    
def make_counter_test():
  mc = make_counter()
  print(mc())
  print(mc())
  print(mc())

 

五、闭包函数

   一、什么是闭包函数

   简单的理解闭包函数就是,内部的函数,不能作用在全局的函数。
#闭包函数定义:定义在函数内部的函数,特点是:包含对外部作用域而不是对全局作用域名字的引用,该函数就称之为闭包函数

# x=1
# def outter():
#     x=2
#     def inner():
#         print(x)
#     return inner


 def counter():
            n=0
            def incr():
                nonlocal n
                x=n
                n+=1
                return x
            return incr

        c=counter()
        print(c())
        print(c())
        print(c())
        print(c.__closure__[0].cell_contents) #查看闭包的元素

  二、闭包的意义与应用

#闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
#应用领域:延迟计算(原来我们是传参,现在我们是包起来)
    from urllib.request import urlopen

    def index(url):
        def get():
            return urlopen(url).read()
        return get

    baidu=index('http://www.baidu.com')
    print(baidu().decode('utf-8'))
复制代码

六、装饰器

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

  一、为何使用装饰器及什么是装饰器

  
#
1、为什么要用装饰器:开放封闭原则,对扩展是开放的,对修改是封闭的 简单说就是 源码不动,在源码(复制一份)的基础上上进行增加,且源码原来的操作调用都是之前的方式。 #2、什么是装饰器 - 用来装饰它人,装饰器本身可以是任意可调用对象,被装饰器的对象也可以是任意可调用对象 - 遵循的原则:1、不修改被装饰对象的源代码 2、不修改被装饰对象的调用方式 - 目标是:在遵循原则1和2的前提,为被装饰器对象添加上新功能 #3.装饰器的举例: #错误的示范,该程序修该了调用方式 # import time # # def index(): # time.sleep(3) # print('welecome to index') # # def timmer(func): # start=time.time() # func() # stop=time.time() # print('run time is %s' %(stop-start)) # # timmer(index)

#正确的装饰器 import time def index(): time.sleep(3) print('welecome to index') def timmer(func): # func=index #最原始的index def inner(): start=time.time() func() #最原始的index stop=time.time() print('run time is %s' %(stop-start)) return inner index=timmer(index) #index=inner # print(f) index() #inner()
https://www.zhihu.com/question/26930016

知乎文章,写的相当不错
如何理解Python装饰器?

 

  二、装饰器的使用

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  #相当于foo=timmer(foo)
def foo():
    time.sleep(3)
    print('from foo')
foo()

def boo():
    time.sleep(3)
    print('from boo')
boo()
无参装饰器
def auth(driver='file'):
    def auth2(func):
        def wrapper(*args,**kwargs):
            name=input("user: ")
            pwd=input("pwd: ")

            if driver == 'file':
                if name == 'egon' and pwd == '123':
                    print('login successful')
                    res=func(*args,**kwargs)
                    return res
            elif driver == 'ldap':
                print('ldap')
        return wrapper
    return auth2

@auth(driver='file')  把egon传给duth 函数
def foo(name):
    print(name)

foo('egon')
有参装饰器

 

  三、装饰器的语法

被装饰函数的正上方,单独一行
        @deco1
        @deco2
        @deco3
        def foo():
            pass

        foo=deco1(deco2(deco3(foo)))

  四、装饰器补充:wraps

    wraps 说简单点就是装饰器的装饰器,在定义使用了装饰器后,加上wraps 可以让原来的装饰器伪装的更像之前的函数。

wraps 的调用方式:
from functools import wraps   #调用wraps 装饰器
def timmer(func):
    @wraps(func)  #直接调用装饰器wraps
    def inner ():
             pass
@timmer
def index(name):
    psdd    
from functools import wraps

def deco(func):
    @wraps(func) #加在最内层函数正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper

@deco
def index():
    '''哈哈哈哈'''
    print('from index')

print(index.__doc__)  #加上wrap后查看index 的注释,如果不加wrap 
                                   #有事一种情况,仔细看执行结果。
wraps 的使用

六、练习

 

posted @ 2017-12-19 23:13  追逐不可能β③  阅读(317)  评论(0编辑  收藏  举报