教你分分钟开发一个属于自己的python模块(一)——能够直接在浏览器打印的方法

  曾经,用惯了python print命令的人,惊叹于python语法的精简;后来,用过了tornado、django等web开发框架,不得不佩服当初开发这些框架的人们。于是,我们开始使用它们的框架==》一个被重复了无数次的配置。那么问题来了,如果我很多次的完成某个领域的类似问题,我需要每次都去重复的配置吗?偶然间,我在想,能否在它们的框架上继续精简,以在某种用途上实现更加高效的开发。web框架的使用,包含server端和browser端。本次改装采用tornado框架。

首先,我们从接触python第一天的print(“Helloworld!”)开始。

干货开始:

  首先我们来看一段精简的tornado代码:

import tornado.ioloop
import tornado.web
 
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
 
application = tornado.web.Application([
    (r"/index", MainHandler),
])
 
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

  上述代码实现了在浏览器端输出hello,world!从上到下各部分的功能依次是:模块导入、业务处理类、路由映射、服务端开启。

本博文详细介绍模块的改装,更多tornado基础内容,详见下面链接:

上述代码虽然实现了在浏览器的输出内容,但是有很多不足之处:

  • 每次打印一个东西,用户都需要写那么多代码
  • 只能支持字符串打印,不能支持字典、列表、元组等常见数据结构

我们知道,python的print用法很简单,只需要我们将需要打印的东西放在print内部,即可用一句话打印出我们想要的结果来。那么问题来了,有没有一种简单的方法能够类似print使用一句话在浏览器上打印出我们想要的任何数据结构?

  答案当然是:有。没错,你没有看错,接下来,博主来带你一步一步实现这个神奇的功能。

模块导入:

import tornado.ioloop
import tornado.web
import json

  和之前有所不同的是,我们增加了json模块,聪明你你应该已经猜到了,博主是想通过json实现对不同数据结构的支持,是的啊,没错!有人说,这不算什么,我也会,好,别走,继续往下看!更多精彩,详见下文!

解决思路:

  事实上,解决这个问题,其实很简单,核心问题就是如何通过传参方式,将用户需要打印的数据传递给self.write。

要解决这个问题,我们需要指定,tornado框架哪些地方可以进行传参,我们再来看一下tornado代码:

import tornado.ioloop
import tornado.web
 
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
 
application = tornado.web.Application([
    (r"/index", MainHandler),
])
 
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

  我们采用由内向外的分析方法:

  • 首先是self.write("Hello, world"),我们希望实现的结果是self.write(arg),arg代表用户传入的参数。而这个arg又要从哪里传入呢?包着它的是get方法,我们知道http协议的get方法可以通过在浏览器的url上通过问号加键值对的方式传入数据,可是难道用户每次打印数据都去浏览器的url输入吗?这明显不合理。因此get方法传参是行不通的。
  • 接下来往外是业务处理类MainHandler,它能传参吗?我们知道类是可以通过init方法进行传参的,每次对类进行实例化的时候进行传参即可,我们需要自己定义个init方法并继承父类的init方法吗?可是问题是,这个MainHandler到底是在哪里进行实例化的,我们又需要在哪里对其进行传参呢?这里就到了tornado的源码部分,可是源码岂能随便去改,因此init方法传参也不合理。
  • 为了遵循对源码封闭,对扩展开放的原则,其实tornado源码中已经为我们预留了位置,这就是传说中的initialize方法,也就是人们所说的“钩子”。

  initialize方法如何使用呢?

首先需要自己定义一个类,用于复写源码中的initialize方法,因为源码中initialize方法其实什么事也没干。

class BaseHandler(tornado.web.RequestHandler):
    def initialize(self,arg):
        self.arg=arg

  在这里,我们为initialize方法传入了参数arg,并给类增加属性self.arg=arg,这样做的目的是为了继承它的子类能够使用这个参数,这就是面向对象的封装,参数传递一次,这个类的子类的所有方法都是可以使用的。没错,聪明的你又发现了,等会如果我们的MainHandler类只要继承了BaseHandler类,那么MainHandler类的get方法中,就可以使用参数self.arg。下面就是MainHandler类的改装。

class MainHandler(BaseHandler):
    def get(self):
        self.write(self.arg)

  做到这里,你可能已经发现:好吧,initialize方法传参我会了,可是用户输入的参数又是如何传入initialize方法呢?

我们发现唯一跟MainHandler类有关的,就是路由映射了,它是一个元组,元组第0个元素是正则匹配,第一个元素是业务处理类的类名,于是博主就想,这里能否接收第三个参数呢?能否进行传参呢?来看一眼路由映射:

application = tornado.web.Application([
        (r"/index", MainHandler, ),
    ])

经过博主对Application类源码进行分析,果然,它是支持传第三个参数的:

源码截图:

源码中spec即每一个元组。更多源码问题,欢迎读者在下方评论,与博主进行探讨。经过博主多方咨询探讨,最终得出结论,第三个参数支持字典格式进行传递(源码中是**kwargs)。

路由映射改装代码:

  application = tornado.web.Application([
        (r"/index", MainHandler, dict(arg=json.dumps(request))),
    ])

同时,为了支持常见数据结构,博主采用json进行序列化数据。

以上就是整个改装流程,下面附整体代码模块和该模块的使用方法。

import tornado.ioloop
import tornado.web
import json

class BaseHandler(tornado.web.RequestHandler):
    def initialize(self,arg):
        self.arg=arg

class MainHandler(BaseHandler):
    def get(self):
        self.write(self.arg)
def print_to_browser(request,port=8888):
    application = tornado.web.Application([
        (r"/", MainHandler, dict(arg=json.dumps(request))),
    ])
    application.listen(port)
    tornado.ioloop.IOLoop.instance().start()

  上述模块是博主原创,封装了tornado路由映射、服务端开启,支持传参,第一个参数即需要打印的内容,第二个参数为可选参数,默认端口8888,如果用户有传递,则以用户输入的参数为准。

鉴于博主有文章被多家网站盗用,鉴于此,原谅博主在此插播声明一条:本博文为博主原创,转账请注明原文链接:http://www.cnblogs.com/wanghzh/p/5869336.html,谢谢合作!

模块使用:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from my.mytornado import print_to_browser  #导入上述模块

print_to_browser([1,2,3,4,]) 

 结果示例截图:

 

  上述使用方法是不是同python自带的print一样简单呢,支持字符串、字典、列表、元组等数据结构。默认域名:127.0.0.1,默认端口:8888。用户只需开启浏览器客户端即可(127.0.0.1:8888)。

如果您觉得本文对您有参考价值,,欢迎帮博主点下文章下方的推荐,非常谢谢!

 

posted @ 2016-09-19 09:17  wangheng1409  阅读(3543)  评论(4编辑  收藏  举报