zoukankan      html  css  js  c++  java
  • Python的学习之旅———函数对象、函数嵌套、名称空间与作用域、装饰器

    一 函数对象

    1 可以被引用

    2 可以当作参数传递

    3 返回值可以是函数

    4 可以当作容器类型的元素

    1 def foo():
    2     print('from foo')
    3  
    4 func=foo
    5  
    6 print(foo)
    7 print(func)
    8 func()

    二 函数嵌套

      函数可以嵌套调用

      嵌套定义

    名称空间:存放名字的地方,准确的说名称空间是存放名字与变量值绑定关系的地方

    一、名称空间又分为:

      内置名称空间:在python解释器启动时产生,存放一些python内置的名字

      全局名称空间:在执行文件时产生,存放文件级别定义的名字

      局部名称空间:在执行文件的过程中,如果调用了函数,则会产生该函数的局部名称空间
      用来存放该函数内定义的名字,该名字在函数调用时生效,在函数调用结束后失效

    二、加载顺序

      加载顺序:内置--->全局--->局部

    三、名字的查找顺序

      局部->全局->内置

    四、作用域

      定义:作用的范围

      一、分为

           全局作用域:全局存活,全局有效:可以用globals()查看

           局部作用域:临时存活,局部有效可以用locals()查看

            二、改变全局变量

            1、可以用global在局部改变全局变量

             声明全局变量,如果在局部要对全局变量修改,需要在局部也要先声明该全局变量:

    2、可变变量可以不需要global在函数内进行修改

    l=[]
    def f2():
        l.append('f2')
    
    f2()
    print(l)

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

    三、作用域关系

    在函数定义时就已经固定于调用位置无关,在调用函数时,必须回到函数原来定义的位置去找作用域关系

    LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__

    locals是函数内的名字空间,包括局部变量和形参

    enclosing 外部嵌套函数的名字空间(闭包中常见)

    globals 全局变量,函数定义所在模块的名字空间

    builtins 内置模块的名字空间

    四 闭包函数

    内部函数包含外部作用域而非全局作用域的引用。

    闭包函数的依据是,函数内部未找到变量相应的值时,会先向上一级函数中寻找

    变量值。

    二 闭包的意义与应用

    为了装饰器做准备 (我是这么觉得的)

    五 装饰器

    装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。

    强调装饰器的原则:

    1 不修改被装饰对象的源代码

    2 不修改被装饰对象的调用方式

    装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

    装饰器的原则:在不修改函数调用方式 和函数本身代码的情况下。增加新功能开放封闭原则,对扩展是开放的,对修改是封闭的。

    无参装饰器

     1 import time
     2 
     3 def timmer(func):
     4     # func=index #最原始的index函数的内存地址
     5     def inner():
     6         start_time=time.time()
     7         func()
     8         stop_time=time.time()
     9         print('run time is :[%s]' %(stop_time-start_time))
    10     return inner
    11 
    12 @timmer #index=timmer(index)
    13 def index():
    14     time.sleep(3)
    15     print('welcome to index page')
    16 index()

    有几点是关键  代码在执行到@timmer 做了两件事

    1将 index()函数名‘index’作为参数传给timmer 于是有了  timmer(index),

    2将timmer()(函数)赋值给了index,(在python中变量名是可以反复使用的,这种操作我觉得就是死皮赖脸的做到调用方式不变的目的)index=timmer()。同时触发函数timmer()。

    inner是一个闭包函数,所以 4 # func=index #最原始的index函数的内存地址 。因为有闭包函数的特性,所以inner在内部的函数func()在寻找func值的时候会向上一层寻找

    于是找到了 func=index。这样就有了inner()内部函数 func()变成了 index(),inner函数最后又将自己return给timmer() ,但此时 inner函数并未触发函数的调用。

    这时index=timmer()实际上是=inner 此时 @timmer的任务就完成了(得到了inderx=inner),代码直接跳到16行进行index() 此时的index()==inner()函数触发.但此时的index()已经不是

    最原始的index()了,而是inner函数,只不过我们想做到调用方式不变而强行使inderx=inner。

    接下来的顺序 5 -6-7-14-15-8-9.

    装饰器 实现的要素

    1 闭包函数找名称空间的时候可以向上一层寻找。
    2 由于作用域的原因 inner函数是无法在外部调用的 但是return打破了层级限制。
    3 变量名是可以反复使用的,使调用方式不变

    装饰器修订

     1 import time
     2 from functools import wraps
     3 
     4 def timmer(func):
     5     @wraps(func)              #help等功能
     6     def inner(*args,**kwargs):
     7         start_time=time.time()
     8         res=func(*args,**kwargs)        
     9         stop_time=time.time()
    10         print('run time is :[%s]' %(stop_time-start_time))
    11         return res                          
    12 
    13     return inner
    14 @timmer
    15 def index():
    16     '''
    17     index function
    18     :return:
    19     '''
    20     time.sleep(3)
    21     print('welcome to index page')
    22     return 123
    23 
    24 @timmer #home=timmer(home) #home=inner
    25 def home(name):
    26     time.sleep(2)
    27     print('welcome %s to home page' %name)
    28     return 456

    为了得到功能函数的返回值, 需要有如下

     8         res=func(*args,**kwargs)        
     9         stop_time=time.time()
    10         print('run time is :[%s]' %(stop_time-start_time))
    11         return res       

    将功能函数的返回值赋给res 然后将res保存下来. 

    有参装饰器

     1 import time
     2 current_status={'user':None,'login_status':False}
     3 def auth(egine='file'):
     4     # egine='file'
     5     def wrapper(func):
     6         def inner(*args,**kwargs):
     7             if current_status['user'] and current_status['login_status']:
     8                 res = func(*args, **kwargs)
     9                 return res
    10 
    11             if egine == 'file':
    12                 u='egon'
    13                 p='123'
    14             elif egine == 'mysql':
    15                 print('mysql auth')
    16                 u = 'egon'
    17                 p = '123'
    18             elif egine == 'ldap':
    19                 print('ldap auth')
    20             else:
    21                 pass
    22             name = input('username>>:').strip()
    23             pwd = input('password>>:').strip()
    24             if name == u and pwd == p:
    25                 print('login successfull')
    26                 current_status['user'] = name
    27                 current_status['login_status'] = True
    28                 res = func(*args, **kwargs)
    29                 return res
    30         return inner
    31     return wrapper
    32 @auth(egine='ldap') #@wrapper #index=wrapper(index) #index=inner
    33 def index():
    34     time.sleep(3)
    35     print('welcome to index page')
    36     return 123

    wrapper 是无参装饰器,现在wrapper内部需要参数egine,所以需要想办法给egine传参,那么我们就用到了闭包函数.wrapper外面再包一个参数,于是有了auth(egine) ,装饰的时候会写为

    @auth(egine) 上面代码写成@auth(egine='file'),只是给了一个默认的初始值.在运行代码时候,见到@auth(egine='file') 先忘了他是装饰器 先执行auth(egine='file')函数 于是得到了return出来的wrapper 于是有了@wrapper 也就是我们的无参装饰器.

    所以有参装饰器的本质 就是无参装饰器的闭包函数.装饰器最多是三层就够了.

    装饰器是有顺序的.修饰下面的代码(如果下面还有多个装饰器).

    有参装饰器有三层  

    1外层  传参给内部的核心功能

    2 中层 作用不改变被装饰函数调用方式

    3 核心层 是内部功能层

    偏函数

    看了一个比较容易理解的例子:

    def add(a,b):

          return a+b;

    add(3,5)

    add(4,7)

    以上两个是我们正常调用,那么如果我们知道一个已知的参数a= 100,我们如何利用偏函数呢?

    import functools import partial as pto

    puls = pto(add,100)

    result = puls(9)

    result的结果就是109。

    在这里偏函数表达的意思就是,在函数add的调用时,我们已经知道了其中的一个参数,我们可以通过这个参数,重新绑定一个函数,就是pto(add,100),然后去调用即可。

    对于有很多可调用对象,并且许多调用都反复使用相同参数的情况,使用偏函数比较合适。

    https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386819893624a7edc0e3e3df4d5d852a352b037c93ec000

  • 相关阅读:
    oracle 监听 添加ip
    重装系统windows
    oracle user pwd
    mybatis
    sum行列合计
    IIS8.5 运行WCF
    exp自动备份在bat中不执行
    oem 重建
    yum install oracle-validated
    MSHflexgrid控件删除选中行
  • 原文地址:https://www.cnblogs.com/surehunter/p/7641909.html
Copyright © 2011-2022 走看看