python由闭包到装饰器

在把函数当作对象的语言(python、javascript)中闭包的概念肯定是少不了的。

闭包的定义
在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。

实例

def Ex(count):
	print(count)
	def e():
        # 内部函数==>用了外部函数的变量
		return count+1
	return e
  • 外函数返回了内函数的引用
  • 外函数把临时变量绑定给内函数

修改变量【非常重要】

想一下python中是如何修改全局变量的?

  • 采用global关键词
  • 将全局变量改为可变的数据类型
    • 可变的数据类型:list 、dict set 【复习笔记中有详细说明】

同理python闭包中内函数如何修改?

  • python3中加入了nonlocal 关键字
  • 采用可变的数据类型【python2 只能采用这种策略了】

使用

def counter(start_at=0):
	count=[start_at]
	def incr():
		count[0]+=1
		return count[0]
	return incr

​ 一个简单的计数器实现计数功能!

>>> c=counter(10)
>>> c()
11
>>> c()
12
>>> 

​ python3 中的实例

>>> def counter(s):
	def add():
		nonlocal s
		s+=1
		return s
	return add

>>> c=counter(10)
>>> c()
11
>>> c()
12

闭包的作用

  1. 装饰器<==>是不是很像呢?
  2. 面向对象<==>属性和方法
  3. 单例模式<==>没用过(难受)

闭包的优缺点

  • 优点:提高代码的复用性
  • 缺点:
    • 由于闭包引用了外部函数的局部变量,外部函数的局部变量没及时释放,消耗内存
    • 闭包类似于实例对象一样,是一个独立空间,多个闭包就是多个各自独立的空间,互不影响
    • 闭包占用的内存空间要远小于一个实例对象的空间,因此在需要一个独立空间(需要变量+功能)时,
      除了考虑实例对象之外,还可以考虑闭包

关于闭包的补充

​ 一切都是对象来说,闭包也有个不得不说的属性即:closure属性定义的cell对象

c=counter(0)
c()
print(c.__closure__[0].cell_contents)
c()
print(c.__closure__[0].cell_contents)
# 输出 1  2

装饰器

​ 在有了前面闭包的理解,下面的装饰器用一个实例引入,比如说我要添加一个自动计数的功能该如何实现?

用闭包实现

def counter(start_at=0):
	count=start_at
	def incr():
		nonlocal count
		count+=1
		return count
	return incr

c=counter()

def output():
    '''
    一堆输出操作
    '''
	print(" %d times" % c())
import time

while True:
	output()
	time.sleep(2)

​ 但是,再用闭包实现时,要改动output()函数中的代码哈,如果不想改变output中的代码该怎么办呢?这就用到装饰器了!

装饰器定义

​ 在不修改原函数的代码的情况下,添加新的功能。可以在执行原函数之前加,也可也在执行原函数之后添加

装饰器用法

def counter(func,count=0):
	def wrapper():
		func()
		nonlocal count
		count+=1
		print(" %d times" %count)
	return wrapper
import time
@counter
def output():
	time.sleep(2)
while True:
	output()

跟闭包差不多,却把函数当参数传递进去了!这就是无参函数的基本用法

函数带参数

# -*- coding: utf-8 -*-

from time import ctime
from time import sleep

def ftfunc(func):
    def timef(*s,**gs):
        print "[%s] %s() called" % (ctime(),func.__name__)
        return func(*s,**gs)
    return timef

@ftfunc
def foo(*s,**gs):
    print(s)
    print(gs)

if __name__ == '__main__':
    foo()
    foo(1)
    foo(1,2)
    foo(1,2,3)
    stu = {'name' : 'alam' ,'age' :12}
    foo(1,2,3,**stu)
'''
运行结果
[Wed Jun 14 15:49:55 2017] foo() called
()
{}
[Wed Jun 14 15:49:55 2017] foo() called
(1,)
{}
[Wed Jun 14 15:49:55 2017] foo() called
(1, 2)
{}
[Wed Jun 14 15:49:55 2017] foo() called
(1, 2, 3)
{}
[Wed Jun 14 15:49:55 2017] foo() called
(1, 2, 3)
{'age': 12, 'name': 'alam'}
[Finished in 0.1s]

'''

装饰器带参数

# -*- coding: utf-8 -*-

def decrator(*dargs, **dkargs):
    def wrapper(func):
        def _wrapper(*args, **kargs):
            print "decrator param:", dargs, dkargs
            print "function param:", args, kargs
            return func(*args, **kargs)
        return _wrapper
    return wrapper

@decrator(1, a=2)
def foo(x, y=0):
    print "foo", x, y


if __name__ == '__main__':
    foo(3, 4)

'''
执行结果
decrator param: (1,) {'a': 2}
function param: (3, 4) {}
foo 3 4
[Finished in 0.1s]
'''

带返回值的装饰器

def counter(func,count=0):
	def wrapper():
		func()
		nonlocal count
		count+=1
		print(" %d times" %count)
		return count
	return wrapper
import time
@counter
def output():
	time.sleep(2)
while True:
	a=output()
	print (a)

多装饰器

import logging
def counter(func,count=0):
	def wrapper():
		func()
		nonlocal count
		count+=1
		print(" %d times" %count)
		return count
	return wrapper
def log(func):
	def wrapper():
		logging.warning("warning test %s" %func.__name__)
		return 0
	return wrapper
import time
@log
@counter
def output():
	time.sleep(2)
while True:
	a=output()
	print (a)
	time.sleep(5)

装饰器是递归输出的!同时可判断! 先输出log 在输出times 返回值是先用那个装饰器就返回谁的
参考链接

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值