转载自 http://python.jobbole.com/80956/html
下面是Flask主页给咱们的第一个例子,咱们如今就由它入手,深刻理解“@app.route()”是如何工做的。python
1
2
3
4
5
|
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
|
@app.route和其它装饰器git
要想明白“@app.route()”的工做原理,咱们首先须要看一看Python中的装饰器(就是以“@”开头的那玩意,下面接着函数定义)。github
究竟什么是装饰器?没啥特别的。装饰器只是一种接受函数(就是那个你用“@”符号装饰的函数)的函数,并返回一个新的函数。服务器
当你装饰一个函数,意味着你告诉Python调用的是那个由你的装饰器返回的新函数,而不单单是直接返回原函数体的执行结果。app
还不是很明白?这里是一个简单的例子:函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# This is our decorator
def simple_decorator(f):
# This is the new function we're going to return
# This function will be used in place of our original definition
def wrapper():
print "Entering Function"
f()
print "Exited Function"
return wrapper
@simple_decorator
def hello():
print "Hello World"
hello()
|
运行上述代码会输出如下结果:
Entering Function
Hello World
Exited Function
很好!测试
如今咱们有点明白怎样建立咱们本身的“@app.route()”装饰器了,但你可能会注意到有一个不一样点,就是咱们的simple_decorator不能够接受任何参数, 但“@app.route()”却能够。this
那么咱们怎样才能给咱们的装饰器传参数?要实现这个咱们只需建立一个“decorator_factory”函数,咱们调用这个函数,返回适用于咱们函数的装饰器。如今看看若是实现它。spa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
def decorator_factory(enter_message, exit_message):
# We're going to return this decorator
def simple_decorator(f):
def wrapper():
print enter_message
f()
print exit_message
return wrapper
return simple_decorator
@decorator_factory("Start", "End")
def hello():
print "Hello World"
hello()
|
给咱们的输出是:
请注意在咱们写@decorator_factory(“Start”, “End”)时,咱们实际调用的是decorator_factory函数,实际返回的装饰器已经被用上了,代码很整洁,对吧?
Start
Hello World
End
把“app”放进“app.route”
如今咱们掌握了装饰器怎样工做的所有前置知识 ,能够从新实现Flask API的这个部分了,那么把咱们的目光转移到“app”在咱们Flask应用中的重要地位上面来。
在开始解释Flask对象里面发生了什么以前,咱们先建立咱们本身的Python类NotFlask。
1
2
3
4
|
class NotFlask():
pass
app = NotFlask()
|
这不是个颇有趣的类,不过有同样值得注意,就是这个类的方法也能够被用做装饰器,因此让咱们把这个类写得更有趣一点,加一个称做 route的方法,它是一个简单的装饰器工厂。
1
2
3
4
5
6
7
8
9
10
11
12
|
class NotFlask():
def route(self, route_str):
def decorator(f):
return f
return decorator
app = NotFlask()
@app.route("/")
def hello():
return "Hello World!"
|
这个装饰器和咱们以前建立的那些最大的不一样,在于咱们不想修改被咱们装饰的函数的行为,咱们只是想得到它的引用。
因此,最后一步是咱们打算去利用一个特性,就是用装饰器函数的副产品去保存一个提供给咱们的路径之间的连接,装饰器函数应该与它关联起来。
为了实现这个,咱们给咱们的NotFlask对象加一个“routes”字典,当咱们的“decorator”函数被调用,路径将被插入新字典中函数对应的位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class NotFlask():
def __init__(self):
self.routes = {}
def route(self, route_str):
def decorator(f):
self.routes[route_str] = f
return f
return decorator
app = NotFlask()
@app.route("/")
def hello():
return "Hello World!"
|
如今咱们就要完成了!可若是无法访问内部的视图函数,保存路径的字典又有什么用?让咱们加入一个方法serve(path),当给定的路径存在时运行一个函数并给们我结果,当路径还没有注册时则抛出一个异常。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
class NotFlask():
def __init__(self):
self.routes = {}
def route(self, route_str):
def decorator(f):
self.routes[route_str] = f
return f
return decorator
def serve(self, path):
view_function = self.routes.get(path)
if view_function:
return view_function()
else:
raise ValueError('Route "{}"" has not been registered'.format(path))
app = NotFlask()
@app.route("/")
def hello():
return "Hello World!"
|
在这个系列咱们只关注重现那些热门库提供的友好API,因此钩挂“serve”方法实现一个HTTP服务器其实有一点超出本文的范围,固然结果是肯定的,运行下述片断:
1
2
3
4
5
6
7
|
app = NotFlask()
@app.route("/")
def hello():
return "Hello World!"
print app.serve("/")
|
咱们会看到:
Hello World!
咱们已经完成了一个的Flask网页上第一个例子的很是简单的重现,让咱们写一些快速测试检测咱们简单重现的Flask的“@app.route()”是否正确。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class TestNotFlask(unittest.TestCase):
def setUp(self):
self.app = NotFlask()
def test_valid_route(self):
@self.app.route('/')
def index():
return 'Hello World'
self.assertEqual(self.app.serve('/'), 'Hello World')
def test_invalid_route(self):
with self.assertRaises(ValueError):
self.app.serve('/invalid')
|
吸口气。
彻底正确!因此,仅仅是一个简单的包含一个字典的装饰器, 就重现了Flask的“app.route()”装饰器的基本的行为。
在本系列的下一篇,也是Flask的app.route()的最后一篇,将经过解析下面这个例子来解释动态URL模式是如何工做。
1
2
3
4
5
|
; html-script: false ]app = Flask(__name__)
@app.route("/hello/<username>")
def hello_user(username):
return "Hello {} !".format(username)
|