Python中的多重装饰器
多重装饰器,即多个装饰器修饰同一个对象【实际上并非完全如此,且看下文详解】
1.装饰器无参数:
>>> def first(func):
print '%s() was post to first()'%func.func_name
def _first(*args,**kw):
print 'Call the function %s() in _first().'%func.func_name
return func(*args,**kw)
return _first
>>> def second(func):
print '%s() was post to second()'%func.func_name
def _second(*args,**kw):
print 'Call the function %s() in _second().'%func.func_name
return func(*args,**kw)
return _second
>>> @first
@second
def test():return 'hello world'
test() was post to second()
_second() was post to first()
>>> test()
Call the function _second() in _first().
Call the function test() in _second().
'hello world'
>>>
实际上它是相当于下面的代码:
>>> def test():
return 'hello world'
>>> test=second(test)
test() was post to second()
>>> test
>>> test=first(test)
_second() was post to first()
>>> test
>>> test()
Call the function _second() in _first().
Call the function test() in _second().
'hello world'
>>>
2.装饰器有参数:
>>> def first(printResult=False):
def _first(func):
print '%s() was post to _first()'%func.func_name
def __first(*args,**kw):
print 'Call the function %s() in __first().'%\
func.func_name
if printResult:
print func(*args,**kw),'#print in __first().'
else:
return func(*args,**kw)
return __first
return _first
>>> def second(printResult=False):
def _second(func):
print '%s() was post to _second()'%func.func_name
def __second(*args,**kw):
print 'Call the function %s() in __second().'%\
func.func_name
if printResult:
print func(*args,**kw),'#print in __second().'
else:
return func(*args,**kw)
return __second
return _second
>>> @first(True)
@second(True)
def test():
return 'hello world'
test() was post to _second()
__second() was post to _first()
>>> test()
Call the function __second() in __first().
Call the function test() in __second().
hello world #print in __second().
None #print in __first().
>>>
如上,第35行输出后调用__second(),而__second()中又调用了test()并print test(),而后返回__first()中继续执行print,而这个print语句print的内容是__second()返回的None
它等同于:
>>> def test():
return 'hello world'
>>> test=second(True)(test)
test() was post to _second()
>>>
>>> test
>>> test=first(True)(test)
__second() was post to _first()
>>> test
>>>
3.多重装饰器的应用:
比如你是项目经理,你要求每一个代码块都必须有参数检查ArgsType和责任检查ResponsibilityRegister,这样就需要两个装饰器对此代码块进行监督。
#coding=utf-8
import os,sys,re
from collections import OrderedDict
def ArgsType(*argTypes,**kwTypes):
u'''ArgsType(*argTypes,**kwTypes)
options=[('opt_UseTypeOfDefaultValue',False)]
以下为本函数相关的开关,并非类型检验相关的关键字参数,所有options:
opt_UseTypeOfDefaultValue=>bool:False,为True时,将对没有指定类型的带默
认值的参数使用其默认值的类型
'''
def _ArgsType(func):
#确定所有的parameter name
argNames=func.func_code.co_varnames[:func.func_code.co_argcount]
#确定所有的default parameter
defaults=func.func_defaults
if defaults:
defaults=dict(zip(argNames[-len(defaults):],defaults))
else:defaults=None
#将“参数类型关键字参数”中的所有“options关键字参数”提出
options=dict()
for option,default in [('opt_UseTypeOfDefaultValue',False)]:
options[option]=kwTypes.pop(option,default)
#argTypes和kwTypes的总长度应该与argNames一致
if len(argTypes)+len(kwTypes)>len(argNames):
raise Exception('Too much types to check %s().'%func.func_name)
#所有kwTypes中的键不能覆盖在argTypes中已经占用的names
if not set(argNames[len(argTypes):]).issuperset(
set(kwTypes.keys())):
raise Exception('There is some key in kwTypes '+
'which is not in argNames.')
#确定所有的参数应该有的types
types=OrderedDict()
for name in argNames:types[name]=None
if len(argTypes):
for i in range(len(argTypes)):
name=argNames[i]
types[name]=argTypes[i]
else:
for name,t in kwTypes.items():
types[name]=t
if len(kwTypes):
for name,t in kwTypes.items():
types[name]=t
#关于default parameter的type
if options['opt_UseTypeOfDefaultValue']:
for k,v in defaults.items():
#如果default parameter的type没有另外指定,那么就使用
#default parameter的default value的type
if types[k]==None:
types[k]=type(v)
def __ArgsType(*args,**kw):
#order the args
Args=OrderedDict()
#init keys
for name in argNames:Args[name]=None
#init default values
if defaults is not None:
for k,v in defaults.items():
Args[k]=v
#fill in all args
for i in range(len(args)):
Args[argNames[i]]=args[i]
#fill in all keyword args
for k,v in kw.items():
Args[k]=v
#check if there is some None in the values
if defaults==None:
for k in Args:
if Args[k]==None:
if defaults==None:
raise Exception(('%s() needs %r parameter, '+
'which was not given')%(func.func_name,k))
else:
if not defaults.has_key(k):
raise Exception(('Parameter %r of %s() is'+
' not a default parameter')%\
(k,func.func_name))
#check all types
for k in Args:
if not isinstance(Args[k],types[k]):
raise TypeError(('Parameter %r of %s() must be '+
'a %r object, but you post: %r')%\
(k,func.func_name,types[k],Args[k]))
return func(*args,**kw)
return __ArgsType
return _ArgsType
def ResponsibilityRegister(author):
def _ResponsibilityRegister(func):
def __ResponsibilityRegister(*args,**kw):
try:
return func(*args,**kw)
except Exception as e:
print ("Something is wrong, It's %s's responsibility."%\
author).center(80,'*')
raise e
return __ResponsibilityRegister
return _ResponsibilityRegister
@ResponsibilityRegister('Kate')
@ArgsType(str,int)
def left(Str,Len=1):
return Str[:Len]
print 'Good calling:'
print left('hello world',8)
print 'Bad calling:'
print left(3,7)
这里没有文档,所以调用者不知道,使用了错误的调用,导致出错,这是Kate的责任。
像上面这种,对代码有两种互不相干的检验时,就可以使用多重装饰器。

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Ramai pemaju laman web menghadapi masalah mengintegrasikan perkhidmatan node.js atau python di bawah seni bina lampu: lampu sedia ada (Linux Apache MySQL PHP) Laman web seni bina memerlukan ...

Penyelesaian kepada Isu Kebenaran Semasa Melihat Versi Python di Terminal Linux Apabila anda cuba melihat versi Python di Terminal Linux, masukkan Python ...

Apabila menggunakan crawler scapy, sebab mengapa fail penyimpanan berterusan paip tidak boleh ditulis? Perbincangan Ketika belajar menggunakan Crawler Scapy untuk Crawler Data, anda sering menemui ...

Proses Python Pool mengendalikan permintaan TCP serentak yang menyebabkan pelanggan terjebak. Apabila menggunakan Python untuk pengaturcaraan rangkaian, adalah penting untuk mengendalikan permintaan TCP serentak dengan cekap. …

Sangat meneroka kaedah tontonan python funcools.partial Object in Funcools.Partial Menggunakan Python ...

Pilihan Perpustakaan Pembangunan Aplikasi Desktop Python Python Banyak pemaju Python ingin membangunkan aplikasi desktop yang boleh dijalankan pada kedua-dua sistem Windows dan Linux ...

Bermula dengan Python: Lukisan Grafik Hourglass dan Pengesahan Input Artikel ini akan menyelesaikan masalah definisi berubah -ubah yang dihadapi oleh pemula python dalam program lukisan grafik Hourglass. Kod ...

Ramai pemaju bergantung kepada PYPI (PythonPackageIndex) ...
