装饰器

# 验证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_result main_result = main_func(request, *args, **kwargs) if main_result != None: return main_result after_result = after_func(request, *args, **kwargs) if after_result != None: return after_result return wrapper() return outer() #==========两个实用的Python的装饰器实例=========# # 第一式:超时函数 '''这个函数的作用在于可以给任意可能会hang住的函数添加超时功能, 这个功能在编写外部API调用 、网络爬虫、数据库查询的时候特别有用。timeout装饰器的代码如下:''' # 下面会用到signal, functools两个库, 定义一个Exception,后面超时抛出 class TimeoutError(Exception): pass def 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 result return 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 localtrace return None def localtrace(frame, why, arg): if why == "line": # record the file name and line number of every trace filename = frame.f_code.co_filename lineno = frame.f_lineno bname = os.path.basename(filename) print("{}({}): {}".format(bname,lineno,linecache.getline(filename, lineno)),) return localtrace def _f(*args, **kwds): sys.settrace(globaltrace) result = f(*args, **kwds) sys.settrace(None) return result return _f # 使用: @trace def xxx(): print(1) print(22) print(333)
闭包

def make_addr(adden): def addr(args): return args + adden return addr m1 = make_addr(23) m2 = make_addr(44) >>> print(m1(100)) 123 >>> print(m2(100)) 144
反射

class Student(object): @property def birth(self): return self._birthday @birth.setter def birth(self, birthday): self._birthday = birthday s = 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] = value j = 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'))