教你分分钟开发一个属于自己的python模块(一)——能够直接在浏览器打印的方法
曾经,用惯了python print命令的人,惊叹于python语法的精简;后来,用过了tornado、django等web开发框架,不得不佩服当初开发这些框架的人们。于是,我们开始使用它们的框架==》一个被重复了无数次的配置。那么问题来了,如果我很多次的完成某个领域的类似问题,我需要每次都去重复的配置吗?偶然间,我在想,能否在它们的框架上继续精简,以在某种用途上实现更加高效的开发。web框架的使用,包含server端和browser端。本次改装采用tornado框架。
首先,我们从接触python第一天的print(“Helloworld!”)开始。
干货开始:
首先我们来看一段精简的tornado代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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使用一句话在浏览器上打印出我们想要的任何数据结构?
答案当然是:有。没错,你没有看错,接下来,博主来带你一步一步实现这个神奇的功能。
模块导入:
1 2 3 | import tornado.ioloop import tornado.web import json |
和之前有所不同的是,我们增加了json模块,聪明你你应该已经猜到了,博主是想通过json实现对不同数据结构的支持,是的啊,没错!有人说,这不算什么,我也会,好,别走,继续往下看!更多精彩,详见下文!
解决思路:
事实上,解决这个问题,其实很简单,核心问题就是如何通过传参方式,将用户需要打印的数据传递给self.write。
要解决这个问题,我们需要指定,tornado框架哪些地方可以进行传参,我们再来看一下tornado代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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方法其实什么事也没干。
1 2 3 | class BaseHandler(tornado.web.RequestHandler): def initialize( self ,arg): self .arg = arg |
在这里,我们为initialize方法传入了参数arg,并给类增加属性self.arg=arg,这样做的目的是为了继承它的子类能够使用这个参数,这就是面向对象的封装,参数传递一次,这个类的子类的所有方法都是可以使用的。没错,聪明的你又发现了,等会如果我们的MainHandler类只要继承了BaseHandler类,那么MainHandler类的get方法中,就可以使用参数self.arg。下面就是MainHandler类的改装。
1 2 3 | class MainHandler(BaseHandler): def get( self ): self .write( self .arg) |
做到这里,你可能已经发现:好吧,initialize方法传参我会了,可是用户输入的参数又是如何传入initialize方法呢?
我们发现唯一跟MainHandler类有关的,就是路由映射了,它是一个元组,元组第0个元素是正则匹配,第一个元素是业务处理类的类名,于是博主就想,这里能否接收第三个参数呢?能否进行传参呢?来看一眼路由映射:
1 2 3 | application = tornado.web.Application([ (r "/index" , MainHandler, ), ]) |
经过博主对Application类源码进行分析,果然,它是支持传第三个参数的:
源码截图:
源码中spec即每一个元组。更多源码问题,欢迎读者在下方评论,与博主进行探讨。经过博主多方咨询探讨,最终得出结论,第三个参数支持字典格式进行传递(源码中是**kwargs)。
路由映射改装代码:
1 2 3 | application = tornado.web.Application([ (r "/index" , MainHandler, dict (arg = json.dumps(request))), ]) |
同时,为了支持常见数据结构,博主采用json进行序列化数据。
以上就是整个改装流程,下面附整体代码模块和该模块的使用方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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,谢谢合作!
模块使用:
1 2 3 4 5 | #!/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)。
如果您觉得本文对您有参考价值,,欢迎帮博主点下文章下方的推荐,非常谢谢!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?