装饰器
# 验证session的装饰器, 在web框架中可以重复使用 def authForm(func):def wrapper(request, *args, **kwargs):if request.session.get['username']:return func(request, *args, **kwargs)else:return render(request, 'login.html')return wrapper# 为函数执行前和函数执行后增加功能的装饰器 def filter(before_func, after_func):def outer(main_func):def wrapper(request, *args, **kwargs):before_result = before_func(request, *args, **kwargs)if before_func != None:return before_resultmain_result = main_func(request, *args, **kwargs)if main_result != None:return main_resultafter_result = after_func(request, *args, **kwargs)if after_result != None:return after_resultreturn wrapper()return outer()#==========两个实用的Python的装饰器实例=========# # 第一式:超时函数 '''这个函数的作用在于可以给任意可能会hang住的函数添加超时功能, 这个功能在编写外部API调用 、网络爬虫、数据库查询的时候特别有用。timeout装饰器的代码如下:''' # 下面会用到signal, functools两个库, 定义一个Exception,后面超时抛出 class TimeoutError(Exception):passdef timeout(seconds, error_message = 'Function call timed out'):def decorated(func):def _handle_timeout(signum, frame):raise TimeoutError(error_message)def wrapper(*args, **kwargs):signal.signal(signal.SIGALRM, _handle_timeout)signal.alarm(seconds)try:result = func(*args, **kwargs)finally:signal.alarm(0)return resultreturn functools.wraps(func)(wrapper)return decorated# 使用:限定下面的slowfunc函数如果在5s内不返回就强制抛TimeoutError Exception结束 @timeout(5) def slowfunc(sleep_time):time.sleep(sleep_time) #这个函数就是休眠sleep_time秒 slowfunc(3) #sleep 3秒,正常返回没有异常 slowfunc(10) #被终止# 第二式:Trace函数 '''有时候出于演示目的或者调试目的,我们需要程序运行的时候打印出每一步的运行顺序和调用逻辑。 类似写bash的时候的bash -x调试功能,然后Python解释器并没有内置这个十分有用的功能。 Trace装饰器的代码如下:''' def trace(f):def globaltrace(frame, why, arg):if why == "call":return localtracereturn Nonedef localtrace(frame, why, arg):if why == "line":# record the file name and line number of every tracefilename = frame.f_code.co_filenamelineno = frame.f_linenobname = os.path.basename(filename)print("{}({}): {}".format(bname,lineno,linecache.getline(filename, lineno)),)return localtracedef _f(*args, **kwds):sys.settrace(globaltrace)result = f(*args, **kwds)sys.settrace(None)return resultreturn _f# 使用: @trace def xxx():print(1)print(22)print(333)
闭包
def make_addr(adden):def addr(args):return args + addenreturn addrm1 = make_addr(23) m2 = make_addr(44)>>> print(m1(100)) 123 >>> print(m2(100)) 144
反射
class Student(object):@propertydef birth(self):return self._birthday@birth.setterdef birth(self, birthday):self._birthday = birthdays = Student() s.birth = 29 print(s.birth)# 下面这个例子更加清楚简洁的使用了__getattr__和__setattr__ # JsonDict继承dict类,重写dict类__getattr__和__setattr__方法 class JsonDict(dict):def __init__(self, **kw):super().__init__(**kw)def __getattr__(self, attr):try:return self[attr]except KeyError:raise AttributeError(r"'JsonDict' object has no attribute '%s'" % attr)# 可以重写dict,使之通过"."调用def __setattr__(self, attr, value):self[attr] = valuej = JsonDict(name='python', age='28') print(j) print(j.name) print(j.age)"""现在很多网站都搞REST API,比如新浪微博、豆瓣啥的,调用API的URL类似: http://api.server/user/friends http://api.server/user/timeline/list 如果要写SDK,给每个URL对应的API都写一个方法,那得累死,而且,API一旦改动,SDK也要改。 利用完全动态的__getattr__,我们可以写出一个链式调用:"""class Chain(object):def __init__(self, path=''):self._path = path# 所有Chain.xx的方法都能通过,可以使用raise AttributeError可以限制传入的参数def __getattr__(self, path):return Chain('%s/%s' % (self._path, path))def __str__(self):return self._path__repr__ = __str__def test(self):pass# 测试结果如下: """ >>> Chain().status.user.timeline.list '/status/user/timeline/list' >>> Chain(http://api.server).status.user.timeline.list 'http://api.server/status/user/timeline/list' """c = Chain() print(hasattr(c, 'best')) print(getattr(c, 'best'))