函数和常用模块1 装饰器

主要内容

  1. 装饰器的定义
  2. 装饰器的重要性
  3. 装饰器的原则
  4. 装饰器理解以及操作

装饰器的定义

本质是函数。(装饰其他函数) 它可以让其他函数在不需要做任何代码变动的前提下增加额外功能。

装饰器的重要性

比如:已经上线的生产环境上有100个函数,需要增加新功能,新增功能不能修改源代码,也不能修改原函数的,这个时候就用到了装饰器。

装饰器经常有切面需求的场景,比如:插入日志,性能测试,事务处理,缓存,权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。 概括的讲,装饰的作用就是为已经存在的对象添加额外的功能。

例子:

import time
def timmer(func):
    def warpper(*args,**kwargs):
        start_time = time.time()
        func()
        stop_time = time.time()
        print('the func run time os %s' %(stop_time-start_time))
    return warpper()

@timmer
def test1():
    time.sleep(3)
    print('in the test1')

test1()

装饰器的原则

  1. 不能修改被装饰函数的源代码.

  2. 不能修改被装饰得函数的调用方式.

  3. 不修改返回结果.

装饰器都函数来说是透明的。

装饰器理解以及操作

函数即“变量”

def test():
        pass

相当于将函数体赋值给test的变量。 变量直接调用变量名,函数是函数名调用 test='函数体' test()

例子1:

将foo()函数体放入房间,然后通过foo()这个门牌号调用函数体,函数体按顺序执行, 当执行到bar()时候,没有门牌号对应。

例子2:

def bar():
     print('in the bar')
def foo():
     print('in the foo')
     bar()
foo()

#######
def foo():
     print('in the foo')
     bar()
def bar():
    print('in the bar')
foo()

上面两个时没有区别的,上面即可正常执行。 函数先定义后调用。调用之前已经解释器解释过了。就能调用成功。 将def bar() def foo()看成函数体。

高阶函数

  1. 把一个函数名当做实参转给另外一个函数 (在不修改被装饰函数源代码的情况下为其添加功能)。

  2. 返回值中包含函数名(不修改函数的调用方式)。

  3. 例子. 把一个函数名当做实参转给另外一个函数

bar 相当于门牌号,调用内存地址。

import time
def bar():
    time.sleep(3)
    print('in the bar')
def test1(func):
    start_time = time.time()
    func() #run bar
    stop_time = time.time()
    print('the func run time is %s' %(stop_time-start_time))

test1(bar)
运行结果:

in the bar
the func run time is 3.0036139488220215

相对于装饰器,调用方式被改变了,这要是在生产环境上功能上是不允许的。

  1. 返回值中包含函数名 例如:
import time

def bar():
    time.sleep(3)
    print('in the bar')

def test2(func):
    print(func)
    return func

#print(test2(bar))
t=test2(bar)
t()

bar=test2(bar)
bar()
运行结果:
<function bar at 0x102519400>
in the bar
<function bar at 0x102519400>
in the bar

没有改变调用方式。

嵌套函数

顾名思义就是函数里面套函数。 函数嵌套,在一个函数体内用def定义而不是调用另外一个函数。

例如:

def foo():
    print('in the foo')
    def bar():
        print('in the bar')
    bar()
foo()
运行结果:
in the foo
in the bar

局部作用域和全局作用域

在函数外,一段代码最始开所赋值的变量,它可以被多个函数引用,这就是全局变量; 在函数内定义的变量名,只能被函数内部引用,不能在函数外引用这个变量名,这个变量的作用域就是局部的,也叫它为局部变量;

如果函数内的变量名与函数外的变量名相同,也不会发生冲突。好比下面这种情况:

x =0
def  grandpa():
    x=1
    def dad():
        x=2
        def son():
            x=3
            print(x)
        son()
    dad()
grandpa()
运行结果为:
3

x = 0这个赋值语句所创建的变量X,作用域为全局变量; x = 3这个赋值语句所创建的变量X,它的作用域则为局部变量,只能在函数son()内使用。

x = 2这个赋值语句所创建的变量X,它的作用域则为局部变量,只能在函数dad()内使用。

x = 1这个赋值语句所创建的变量X,它的作用域则为局部变量,只能在函数grandpa()内使用。

尽管这两个变量名是相同的,但它的作用域为它们做了区分。作用域在某种程度上也可以起到防止程序中变量名冲突的作用,但如果做为玩蛇网python初学者来说,尽量避免这种情况发生比较好。

高阶函数+嵌套函数=》装饰器

简单装饰器例子

@语法糖

import time
def timer(func): #timer(test1) func=test1
    def deco():
        start_time = time.time()
        func()
        stop_time = time.time()
        print('the func run time %s' % (stop_time - start_time))
    return deco

@timer   #timer(test1) func=test1
def test1():
    time.sleep(3)
    print('in the test1')
@timer
def test2():
    time.sleep(3)
    print('in the test2')

#test1=timer(test1)  #返回的是deco的内存地址
test1() #相当于运行test1
#test2=timer(test2)  #返回的是deco的内存地址
test2() #相当于运行test2

运行结果:
in the test1
the func run time 7.023896217346191
in the test2
the func run time 7.066271066665649

传参数的装饰器例子

import time
def timer(func): #timer(test1) func=test1
    def deco(*args,**kwargs):
        start_time = time.time()
        func(*args,**kwargs)
        stop_time = time.time()
        print('the func run time %s' % (stop_time - start_time))
    return deco

@timer   #test1= timer(test1)
def test1():
    time.sleep(3)
    print('in the test1')

@timer #test2=timer(test2) = deco  test2(name)=deco(name)
def test2(name,age):
    print('test2', name,age)

test1()
test2('cathy',22)
运行结果:
in the test1
the func run time 3.003638982772827
test2 cathy 22
the func run time 3.409385681152344e-05

用户验证场景装饰器

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Cathy Wu
user,passwd='cathy','abc123'
def auth(auth_type):
    print('auth fucn:',auth_type)
    def outer_warpper(func):
        def wrapper(*args, **kwargs):
            print('wrapper func args:',*args, **kwargs)
            if auth_type == 'local':
                username = input('username:').strip()
                password = input('password:').strip()

                if user == username and passwd == password:
                    print('\033[32;1m User has passed  authenticaiton\033[0m')
                    res = func(*args, **kwargs)
                    print('after authenticaiton')
                    return res
                else:
                    exit('\033[32;1m Invalid passwodr or username\033[0m')
            elif auth_type == 'ldap':
                print('ldap authenticaiton')
        return wrapper
    return outer_warpper

def index():
    print('welcome to the index')

@auth(auth_type='local')
def home():
    print('welcome to the home')
    return "from home"

@auth(auth_type='ldap')
def bbs():
    print('welcome to the bbs')

index()
print(home())
bbs()
运行结果:
auth fucn: local
auth fucn: ldap
welcome to the index
wrapper func args:
username:cathy
password:abc123
 User has passed  authenticaiton
welcome to the home
after authenticaiton
from home
wrapper func args:
ldap authenticaiton

参考网页

http://www.cnblogs.com/alex3714/articles/5765046.html

http://egon09.blog.51cto.com/9161406/1836763

http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html

posted @ 2017-07-27 17:18  cathywu  阅读(416)  评论(0)    收藏  举报