装饰器

装饰器

-----在代码运行期间动态的增加功能的方式,本质上是一个返回函数的高阶函数

功能:插入场景,性能测试,事务处理,达到代码重用的目的

函数是一个对象,可赋值给变量:

def time():
	print'2017-7-19'

f = time
f()

>>> 2017-7-19 
函数对象的_name_函数,可以拿到函数的名字:

print time.__name__
print f.__name__

>>>time
>>>time
初步定义一个简单的装饰器:

def deco(func):
	print 'my %s():'%func.__name__

def time():
	print '2017-7-9'

deco(time)
time()

>>>my time():
>>>2017-7-9
缺点:所有的“time”调用处都要改为“deco(time)”

改进:避免装饰器deco对“time”函数的调用代码的影响,增加一个内嵌函数wrapper

ef deco(func):#装饰器接受一个函数作为参数,并返回一个函数
	def wrapper():#wrapper-->包装
		print 'my %s():'%func.__name__
		return func()
	return wrapper

def time():
	print'2017-7-9'

time = deco(time)
time()

>>>my time():
>>>2017-7-9
装饰器语法糖:用“”语法糖来精简装饰器的代码:

def deco(func):
	def wrapper():
		print 'my %s():'%func.__name__
		return func()
	return wrapper

@deco#相当于time = deco(time),则不需要额外代码来给“time”重新赋值
def time():
	print '2017-7-9'

time()

>>>my time():
>>>2017-7-9
两层嵌套--->被装饰的函数带参数:

def deco(func):
	def wrapper(a,b):#在内嵌函数中加上同样的参数
		print 'a + b =',a + b
		return func(a,b)
	return wrapper

@deco#相当于time = deco(time(1,2))
def time(a,b):
	print '2017-7-9'

time(1,2)

>>>my time():
>>>2017-7-9
>>>a + b = 3
>>>2017-7-9
???如果多个函数拥有不同的参数形式,怎么共用同样的装饰器:

在Python中,函数支持(*args,**kw)可变参数,所以内嵌函数可以通过可变参数来实现

三层嵌套--->带参数的装饰器:

def deco_(text):
	def deco(func):
		def wrapper(*args,**kw):
			print '%s %s():'%(text,func.__name__)
			return func(*args,**kw)
		return wrapper
	return deco

@deco_('my')#相当于deco_(’my‘)(time)
def time():
	print '2017-7-9'

time()

>>>my time():
>>>2017-7-9
程序分析:首先执行deco_('my'),返回的是deco函数,再调用返回的函数,参数是time函数,返回值最终是wrapper函数

因此,返回的名字由time变为wrapper:

def deco(func):
	def wrapper(*args,**kw):
		print '%s'%func.__name__
		return func(*args,**kw)
	return wrapper

@deco
def time():
	print time.__name__

time()

>>>time
>>>wrapper
因此,需要把原始函数的_name_等属性复制到wrapper函数中,否则,有些依赖函数签名的代码执行就会出错

因为Python中有内置的函数functools.wraps代替了wrapper._name_ = func._name_ ,则只需要在内嵌函数wrapper前面加上“@functools.wraps(func)

import functools

def deco(func):
	@functools.wraps(func)
	def wrapper(*args,**kw):
		print '%s' %func.__name__
		return func(*args,**kw)
	return wrapper

@deco
def time():
	print time.__name__

time()

>>>time
>>>time
调用顺序:与声明的顺序相反

def deco_1(func):
	print '调用deco_1'
	def wrapper(*args,**kw):
		print '调动deco_1的wrapper'
		return func(*args,**kw)
	return wrapper

def deco_2(func):
	print '调用deco_2'
	def wrapper(*args,**kw):
		print '调用deco_2的wrapper'
		return func(*args,**kw)
	return wrapper

@deco_1
@deco_2
def order():
	pass

order()#即deco_1(deco_2(order))

>>>调用deco_2
>>>调用deco_1
>>>调动deco_1的wrapper
>>>调用deco_2的wrapper


习题:

习题一:请编写一个decorator,能在函数调用的前后打印出'begin call''end call'的日志。

import functools

def deco(func):
	@functools.wraps(func)
	def wrapper(*args, **kw):
		print 'begin call %s()'%func.__name__
		func(*args, **kw)
		print 'end call %s()' % func.__name__
		#return func(*args, **kw)
	return wrapper

@deco
def diary():
	print '2017-7-9'

diary()

>>>begin call diary()
>>>2017-7-9
>>>end call diary()
习题二:能否写出一个@log的deco,使它既支持:@log                     又支持:   @log('test')

                                    def  f():                                              def  f():

                                       pass                                                  pass

def log(*text):
	def deco(func):
		@functools.wraps(func)
		def wrapper(*args, **kw):
			if len(text) == 0:
				print'log无输入参数'
			else:
				for i in text:
					print'log输入了参数:%s'%i
			return func(*args, **kw)
		return wrapper
	return deco

@log('my','deco')
@log()
def test():
	pass

test()

>>>log输入了参数:my
>>>log输入了参数:deco
>>>log无输入参数




下载方式:https://pan.quark.cn/s/a4b39357ea24 布线问题(分支限界算法)是计算机科学和电子工程领域中一个广为人知的议题,它主要探讨如何在印刷电路板上定位两个节点间最短的连接路径。 在这一议题中,电路板被构建为一个包含 n×m 个方格的矩阵,每个方格能够被界定为可通行或不可通行,其核心任务是定位从初始点到最终点的最短路径。 分支限界算法是处理布线问题的一种常用策略。 该算法与回溯法有相似之处,但存在差异,分支限界法仅需获取满足约束条件的一个最优路径,并按照广度优先或最小成本优先的原则来探索解空间树。 树 T 被构建为子集树或排列树,在探索过程中,每个节点仅被赋予一次成为扩展节点的机会,且会一次性生成其全部子节点。 针对布线问题的解决,队列式分支限界法可以被采用。 从起始位置 a 出发,将其设定为首个扩展节点,并将与该扩展节点相邻且可通行的方格加入至活跃节点队列中,将这些方格标记为 1,即从起始方格 a 到这些方格的距离为 1。 随后,从活跃节点队列中提取队首节点作为下一个扩展节点,并将与当前扩展节点相邻且未标记的方格标记为 2,随后将这些方格存入活跃节点队列。 这一过程将持续进行,直至算法探测到目标方格 b 或活跃节点队列为空。 在实现上述算法时,必须定义一个类 Position 来表征电路板上方格的位置,其成员 row 和 col 分别指示方格所在的行和列。 在方格位置上,布线能够沿右、下、左、上四个方向展开。 这四个方向的移动分别被记为 0、1、2、3。 下述表格中,offset[i].row 和 offset[i].col(i=0,1,2,3)分别提供了沿这四个方向前进 1 步相对于当前方格的相对位移。 在 Java 编程语言中,可以使用二维数组...
源码来自:https://pan.quark.cn/s/a4b39357ea24 在VC++开发过程中,对话框(CDialog)作为典型的用户界面组件,承担着与用户进行信息交互的重要角色。 在VS2008SP1的开发环境中,常常需要满足为对话框配置个性化背景图片的需求,以此来优化用户的操作体验。 本案例将系统性地阐述在CDialog框架下如何达成这一功能。 首先,需要在资源设计工具中构建一个新的对话框资源。 具体操作是在Visual Studio平台中,进入资源视图(Resource View)界面,定位到对话框(Dialog)分支,通过右键选择“插入对话框”(Insert Dialog)选项。 完成对话框内控件的布局设计后,对对话框资源进行保存。 随后,将着手进行背景图片的载入工作。 通常有两种主要的技术路径:1. **运用位图控件(CStatic)**:在对话框界面中嵌入一个CStatic控件,并将其属性设置为BST_OWNERDRAW,从而具备自主控制绘制过程的权限。 在对话框的类定义中,需要重写OnPaint()函数,负责调用图片资源并借助CDC对象将其渲染到对话框表面。 此外,必须合理处理WM_CTLCOLORSTATIC消息,确保背景图片的展示不会受到其他界面元素的干扰。 ```cppvoid CMyDialog::OnPaint(){ CPaintDC dc(this); // 生成设备上下文对象 CBitmap bitmap; bitmap.LoadBitmap(IDC_BITMAP_BACKGROUND); // 获取背景图片资源 CDC memDC; memDC.CreateCompatibleDC(&dc); CBitmap* pOldBitmap = m...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值