Last active
August 24, 2019 08:54
-
-
Save ssut/6ecf93fac9457dd623b0 to your computer and use it in GitHub Desktop.
Python decorator endpoint implementation (like Flask blueprint module) - O(1)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#-*- coding: utf-8 -*- | |
import time | |
from collections import namedtuple | |
from test import ep as app | |
BenchResult = namedtuple('BenchResult', ['str', 'time']) | |
def benchmark(str, times=100000): | |
t_start = time.time() | |
for i in range(times): | |
app(str) | |
t_end = time.time() | |
result = BenchResult(str=str, time=t_end - t_start) | |
return result | |
if __name__ == '__main__': | |
print benchmark(u'안녕') | |
print benchmark(u'ㅎㅇ') | |
print benchmark(u'가나다') | |
print benchmark(u'가나라마') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#-*- coding: utf-8 -*- | |
import inspect | |
import re | |
def endpoint_from_func(func): | |
assert func is not None, 'expected func if endpoint is not provided.' | |
return func.__name__ | |
class Endpoint(object): | |
def __init__(self): | |
self.rules = [] | |
self.functions = {} | |
def __call__(self, *args): | |
return self.dispatch(*args) | |
@property | |
def routes(self): | |
routes = [] | |
routes.append(' %-30s| %-20s| %-16s' % ('Rule', 'Endpoint Function', 'Arguments')) | |
for regex, endpoint in self.rules: | |
args = tuple(inspect.getargspec(self.functions[endpoint]).args) | |
route = ' %-30s| %-20s| %-16s' % (regex.pattern, endpoint, args) | |
route = u' {:30s}| {:20s}| {:16s}'.format(regex.pattern, endpoint, args) | |
routes.append(route) | |
return '\n'.join(routes) | |
def route(self, rule, **options): | |
def decorator(f): | |
endpoint = options.pop('endpoint', None) | |
self.add_rule(rule, endpoint, f, **options) | |
return f | |
return decorator | |
def add_rule(self, rule, endpoint=None, func=None, **options): | |
""" | |
Basically this example: | |
@app.route('f') | |
def foo(): | |
pass | |
Is equivalent to the following: | |
def foo(): | |
pass | |
app.add_rule('f', 'foo', foo) | |
""" | |
if endpoint is None: | |
endpoint = endpoint_from_func(func) | |
options['endpoint'] = endpoint | |
if func is not None: | |
old_func = self.functions.get(endpoint) | |
if old_func is not None and old_func != func: | |
raise AssertionError('function mapping is overwriting an ' | |
'existing endpoint function: %s', endpoint) | |
self.functions[endpoint] = func | |
if not options.has_key('re'): | |
rule = re.compile('^' + re.escape(rule) + '$') | |
else: | |
rule = re.compile(rule) | |
rule = (rule, endpoint) | |
self.rules.append(rule) | |
def dispatch(self, rule, *args): | |
matches = ( | |
(regex.match(rule), ep) for regex, ep in self.rules | |
) | |
# print matches | |
matches = ( | |
(match.groups(), ep) for match, ep in matches if match is not None | |
) | |
for args, endpoint in matches: | |
return self.functions[endpoint](*args) | |
return None |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#-*- coding: utf-8 -*- | |
from endpoint import Endpoint | |
ep = Endpoint() | |
@ep.route(u'^안녕', re=True) | |
def hello(): | |
return u'안녕' | |
@ep.route(u'ㅎㅇ') | |
@ep.route(u'안뇽') | |
def hello_multiple_route(): | |
return u'안녕!' | |
@ep.route(u'가나(다|라)(마)?', re=True) | |
def test2(dara, ma): | |
return '%s %s' % (dara, ma) | |
if __name__ == '__main__': | |
# Call hello function | |
print ep(u'안녕') | |
# Call hello_multiple_route function | |
print ep(u'ㅎㅇ') | |
# Call test2 function with one(dara) parameter | |
print ep(u'가나다') | |
# Call test2 function with two(dara, ma) parameter | |
print ep(u'가나라마') | |
print ep.routes | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Benchmark Result
Processor: Intel Core i7-4770 CPU @ 3.40GHz
Benchmark count: 100,000
Windows 7 + Cygwin x64 + Python 2.7.5
Windows 7 + Python 2.7.6