安装

pip install bottle

示例程序

from bottle import Bottle, run, template

app = Bottle()

@app.route("/")

def index():

return "bottle index"

@app.route("/hello/")

def hello(name="Stranger"):

return template("hellp {{name}}", name=name)

run(app, host="0.0.0.0", port=8888, debug=True, reloader=True)

请求路由

动态路由

:int 只匹配(有符号)数字,并将值转换为整数。

浮标 类似于:int,但用于十进制数。

路径 以非贪婪的方式匹配所有字符,包括斜线字符,并且可以用于匹配多个路径段。

:re 允许您在配置字段中指定自定义正则表达式。不修改匹配的值。

@route('/object/')

def callback(id):

assert isinstance(id, int)

@route('/show/')

def callback(name):

assert name.isalpha()

@route('/static/')

def callback(path):

return static_file(path, ...)

实现自己的过滤器

app = Bottle()

def list_filter(config):

''' Matches a comma separated list of numbers. '''

delimiter = config or ','

regexp = r'\d+(%s\d)*' % re.escape(delimiter)

def to_python(match):

return map(int, match.split(delimiter))

def to_url(numbers):

return delimiter.join(map(str, numbers))

return regexp, to_python, to_url

app.router.add_filter('list', list_filter)

@app.route('/follow/')

def follow_users(ids):

for id in ids:

显式路由配置

def setup_routing(app):

app.route('/new', ['GET', 'POST'], form_new)

app.route('/edit', ['GET', 'POST'], form_edit)

app = Bottle()

setup_routing(app)

路由静态文件

不会主动添加路由和回调,必须自己添加。

这个 static_file() 函数是以安全和方便的方式提供文件的帮助程序 ,此示例仅限于 /path/to/your/static/files 目录,因为 `` 通配符不匹配包含斜杠的路径。若要在子目录中提供文件,请更改通配符以使用 path 过滤器:

from bottle import static_file

@route('/static/')

def server_static(filename):

return static_file(filename, root='/path/to/your/static/files')

错误页面

如果出了什么问题, Bottle 会显示一个信息丰富但相当简单的错误页面。您可以使用 error() 装饰:

from bottle import error

@error(404)

def error404(error):

return 'Nothing here, sorry'

从今以后, 404 File not Found 错误将向用户显示自定义错误页。传递给错误处理程序的唯一参数是 HTTPError, 除此之外,错误处理程序与常规请求回调非常相似。你可以阅读request给response并返回HTTPError实例

配置文件

基础知识

import bottle

app = bottle.default_app() # or bottle.Bottle() if you prefer

app.config['autojson'] = False # Turns off the "autojson" feature

app.config['sqlite.db'] = ':memory:' # Tells the sqlite plugin which db to use

app.config['myapp.param'] = 'value' # Example for a custom config value.

# Change many values at once

app.config.update({

'autojson': False,

'sqlite.db': ':memory:',

'myapp.param': 'value'

})

# Add default values

app.config.setdefault('myapp.param2', 'some default')

# Receive values

param = app.config['myapp.param']

param2 = app.config.get('myapp.param2', 'fallback value')

# An example route using configuration values

@app.route('/about', view='about.rst')

def about():

email = app.config.get('my.email', 'nomail@example.com')

return {'email': email}

app对象不一定总是可用的,但只要你在处理一个请求,你可以使用 request 对象来获得当前的应用对象和它的配置:

from bottle import request

def is_admin(user):

return user == request.app.config['myapp.admin_user']

命名约定

方便起见,插件和应用应该遵循一些简单的规则,特别是在给配置参数命名的时候:

所有的key都应该是小写的字符串,并符合Python的变量命名规则(除了下划线外,没有特殊字符)。

命名空间通过点来区分(例如: namespace.field 或 namespace.subnamespacew.field )。

Bottle框架,使用根命名空间来存储它的配置。插件应该在它们自己的命名空间中存储它们的变量(例如: sqlite.db或werkzeug.use_debugger` )。

你的应用应该使用一个独立的命名空间(例如: myapp.* )。

从文件中加载配置

在你不想通过修改代码来修改配置的时候,配置文件是非常有用的。常见的配置文件语法如下:

[sqlite]

db = /tmp/test.db

commit = auto

[myapp]

admin_user = defnull

app.config.load_config('/etc/myapp.conf')

从字典中加载配置

另外一个有用的方法,是 ConfigDict.load_dict() 。将字典中的配置,放到各自的命名空间下面:

# Load an entire dict structure

app.config.load_dict({

'autojson': False,

'sqlite': { 'db': ':memory:' },

'myapp': {

'param': 'value',

'param2': 'value2'

}

})

assert app.config['myapp.param'] == 'value'

# Load configuration from a json file

with open('/etc/myapp.json') as fp:

app.config.load_dict(json.load(fp))

同步WSGI的限制

简单来说, WSGI标准 (pep 3333) 定义了下面这一个request/response的循环:每次请求到达的时候,应用中的callable会被调用一次,返回一个主体iterator。接着服务器会遍历该主体,分块写入socket。遍历完整个主体,就关闭客户端的连接。

足够简单,但是存在一个小问题:所有这些都是同步的。如果你的应用需要等待数据(IO, socket, 数据库, ...),除了返回一个空字符串(忙等),就只能阻塞当前线程。两种办法都会占用当前线程,导致线程不能处理新的请求,只能处理当前的一个请求。

大部分服务器都限制了线程的数量,避免伴随它们而来的资源消耗。常见的是一个线程池,内有20个或更少数量的线程。一旦所有的线程都被占用了,任何新的请求都会阻塞。事实上,对于其他人来说,服务器已经宕机了。如果你想实现一个聊天程序,使用ajax轮询来获取实时消息,很快你就会受到线程数量的限制。这样能同时服务的用户就太少了。

Greenlet

大多数服务器的线程池都限制了线程池中线程的数量,避免创建和切换线程的代价。尽管和创建进程(fork)的代价比起来,线程还是挺便宜的。但是也没便宜到可以接受为每一个请求创建一个线程。

gevent 模块添加了 greenlet 的支持。greenlet和传统的线程类似,但其创建只需消耗很少的资源。基于gevent的服务器可以生成成千上万的greenlet,为每个连接分配一个greenlet也毫无压力。阻塞greenlet,也不会影响到服务器接受新的请求。同时处理的连接数理论上是没有限制的。

这令创建异步应用难以置信的简单,因为它们看起来很想同步程序。基于gevent服务器实际上不是异步的,是大规模多线程。下面是一个例子。

from gevent import monkey; monkey.patch_all()

from time import sleep

from bottle import route, run

@route('/stream')

def stream():

yield 'START'

sleep(3)

yield 'MIDDLE'

sleep(5)

yield 'END'

run(host='0.0.0.0', port=8080, server='gevent')

第一行很重要。它让gevent monkey-patch了大部分Python的阻塞API,让它们不阻塞当前线程,将CPU让给下一个greenlet。它实际上用基于gevent的伪线程替换了Python的线程。这就是你依然可以使用 time.sleep() 这个照常来说会阻塞线程的函数。如果这种monkey-patch的方式感令你感到不舒服,你依然可以使用gevent中相应的函数 gevent.sleep() 。

如果你运行了上面的代码,接着访问 http://localhost:8080/stream ,你可看到 START, MIDDLE, 和 END 这几个字样依次出现(用时大约8秒)。它像普通的线程一样工作,但是现在你的服务器能同时处理成千上万的连接了。

WebSockets

让我们暂时忘记底层的细节,来谈谈WebSocket。既然你正在阅读这篇文章,你有可能已经知道什么是WebSocket了,一个在浏览器(客户端)和Web应用(服务端)的双向的交流通道。

感谢 gevent-websocket 包帮我们做的工作。下面是一个WebSocket的简单例子,接受消息然后将其发回客户端。

from bottle import request, Bottle, abort

app = Bottle()

@app.route('/websocket')

def handle_websocket():

wsock = request.environ.get('wsgi.websocket')

if not wsock:

abort(400, 'Expected WebSocket request.')

while True:

try:

message = wsock.receive()

wsock.send("Your message was: %r" % message)

except WebSocketError:

break

from gevent.pywsgi import WSGIServer

from geventwebsocket import WebSocketError

from geventwebsocket.handler import WebSocketHandler

server = WSGIServer(("0.0.0.0", 8080), app,

handler_class=WebSocketHandler)

server.serve_forever()

while循环直到客户端关闭连接的时候才会终止。You get the idea

python bottle 终止返回_python bottle学习相关推荐

  1. python语言1002python语言_PYTHON语言学习

    PYTHON 语言学习 通过两个星期的自学 python 语言,初步了解到 python 的知识构架.它比 C 语言和 C++ 语 言在某种程度上来说要简单些, 但是也有很多我不懂的东西. 陈老师给我 ...

  2. python数据库操作框架_python bottle 框架操作数据库

    python操作mysql数据库用MySQLdb模板,操作postgresql则用psycopg2模块 安装MySQLdb(用yum安装,好像只能与mysql5.1版本配合使用):yum instal ...

  3. python大作业爬虫_Python爬虫学习-爬取大规模数据(10w级)

    编译环境:python v3.5.0, mac osx 10.11.4 python爬虫基础知识: Python爬虫学习-基础爬取 了解数据库 MongoDB 数据库是储存数据的地方,可以将如下的字典 ...

  4. python爬虫自学路线_python 爬虫学习路线:从入门到进阶

    大家好,我是凉拌 今天给大家详解一下我的爬虫学习路线. 对于小白来说,爬虫可能是一件非常复杂.技术门槛很高的事情.比如有的人则认为先要掌握网页的知识,遂开始 HTML\CSS,结果入了前端的坑,浪费了 ...

  5. python框架怎么学_Python框架学习

    Python框架学习 基于flask框架的MySql数据库交互系统. 1.开发环境 #系统:win10 #python版本:PY3.6 #MySQL版本:MySQL5.6 #开发工具:Pycharm ...

  6. python中向量长度_Python线性代数学习笔记——什么是向量?实现我们自己的向量...

    上一篇已经说明了为什么要学习线性代数? 下面我们正式开始学习 一切从向量开始 什么是向量,究竟为什么引⼊向量? 从研究一个数,变成了研究一组数,向量表示的就是一组数 学过中学物理都知道力,速度,加速度 ...

  7. opencv python 直方图反向投影_python OpenCV学习笔记直方图反向投影的实现

    本文介绍了python OpenCV学习笔记直方图反向投影的实现,分享给大家,具体如下: 它用于图像分割或寻找图像中感兴趣的对象.简单地说,它创建一个与我们的输入图像相同大小(但单通道)的图像,其中每 ...

  8. python 去掉双引号_Python基础学习笔记(一)变量与数据类型

    Python是一门易学的面向对象的程序设计语言,可以轻易地完成界面.文件.封装等高阶需求,可移植性好,有非常多功能强大的库与包,如Numpy(数值计算).SciPy(数学.科学与工程计算).Matpl ...

  9. python 人脸比对_python dlib学习(五):比对人脸

    前言 在前面的博客中介绍了,如何使用dlib标定人脸(python dlib学习(一):人脸检测),提取68个特征点(python dlib学习(二):人脸特征点标定).这次要在这两个工作的基础之上, ...

最新文章

  1. linux显示没有网卡
  2. VB随笔 -基本语句之循环语句
  3. 安装引导黑屏_南京课工场IT培训:引导过程与服务控制(理论笔记篇)
  4. html滚动条样式自定义,如何自定义CSS滚动条的样式?
  5. tcp之backlog参数
  6. 机器学习优化算法中梯度下降,牛顿法和拟牛顿法的优缺点详细介绍
  7. 实验四报告 20135209潘恒 20135204郝智宇
  8. html 自定义属性_五道自测题-你我都应知道的HTML小知识
  9. C++ primer第一章 C++概述 纪要
  10. FreeSWITCH折腾笔记3——数据库修改为postgresql
  11. pygame的安装与使用
  12. word模板文档替换,解决并发导致替换失败
  13. 制作u盘winpe启动盘_Ventoy启动盘制作工具,Win、Linux、PE多系统镜像装进同1个U盘...
  14. Keil 编译显示变量重复定义问题
  15. 银河麒麟高级服务器操作系统V10——安装Tuxedo12
  16. OpenCV剪切图片圆形区域
  17. idea的java项目怎么连数据库_idea 使用Java连接SQL Server数据库教程
  18. 葫芦娃各平台以及微信hook分析汇总
  19. CSS——网页的布局方式
  20. java kumo生成词云

热门文章

  1. 原型链,什么是原型链?原型链的作用
  2. 郑码词库制作for百度输入法
  3. 编译compile_commands.json
  4. 取消烦人的自动代理配置
  5. 浅谈IT的名词变化路程
  6. C++同名成员处理详解
  7. SAP ALV合并单元格示例(合并单元格为表头)
  8. 【MyBatis】延迟加载
  9. 《操作系统——真象还原》书评
  10. EPICS--Sequencer第二部分--编译SNL程序