tornado的options模块是一个命令行解析模块,此模块不仅可以从命令行解析传递的选项,也能从配置文件解析。以下边的事例来进行说明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| from tornado.options import options, define from tornado.web import Application, RequestHandler from tornado.ioloop import IOLoop define("port", default=8000, type=int, help="listen port") class MainHandler(RequestHandler): def get(self, *args, **kwargs): self.write('hello') if __name__ == '__main__': app = Application( [ (r'/', MainHandler) ], debug=True ) app.listen(port=options.port, address='0.0.0.0') IOLoop.current().start()
|
要使用tornado的配置解析功能需要从options
模块中引入options
和define
两个对象,define
函数定义全局命名空间的选项,比如上边定义的port
选项,后边就可以使用tornado.options.options.port
来调用,运行上边的程序可以发现,程序监听在了8000
端口,如下:
1 2 3
| neal@neal-System-Product-Name:~$ ss -tnlp | grep 8000 LISTEN 0 128 *:8000 *:* users:(("python",pid=18033,fd=6)) neal@neal-System-Product-Name:~$
|
如果要让程序可以接受命令行传递的参数,那可以这样来改造程序,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from tornado.options import options, define from tornado.web import Application, RequestHandler from tornado.ioloop import IOLoop define("port", default=8000, type=int, help="listen port") class MainHandler(RequestHandler): def get(self, *args, **kwargs): self.write('hello') if __name__ == '__main__': options.parse_command_line() app = Application( [ (r'/', MainHandler) ], debug=True ) app.listen(port=options.port, address='0.0.0.0') IOLoop.current().start()
|
上边加入了options.parse_command_line()
这一行代码,表示解析命令行传递的参数,参数使用_–name=value_的格式传递,试着运行上边的代码,在命令行传递相应的选项,如下:
1 2 3 4 5 6 7
| (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ python options_test.py --port=8080 (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ ss -tnlp | grep python) LISTEN 0 128 *:8080 *:* users:(("python",pid=20086,fd=6)) (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ python options_test.py (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ ss -tnlp | grep python) LISTEN 0 128 *:8000 *:* users:(("python",pid=20034,fd=6))
|
程序监听在了8080
端口,是从命令行传递过来的,所以可以知道,在define
函数中定义的选项,又定义了options.parse_command_line()
从命令行捕获选项,那程序运行时传递了相应的选项,那程序就使用这个在命令行传递选项的值,如果程序运行时没有传递相应的选项,那就采用define中定义的默认值。
options模块不仅可以从define和命令行获取选项的值,还可以读取指定一个配置文件,从配置文件读取选项和值,请看下边代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from tornado.options import options, define from tornado.web import Application, RequestHandler from tornado.ioloop import IOLoop define("port", default=8000, type=int, help="listen port") class MainHandler(RequestHandler): def get(self, *args, **kwargs): self.write('hello') if __name__ == '__main__': options.parse_config_file('./application.conf') app = Application( [ (r'/', MainHandler) ], debug=True ) app.listen(port=options.port, address='0.0.0.0') IOLoop.current().start()
|
applications.conf格式如下:
1 2
| (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ cat application.conf port = 8080
|
程序运行后可发现程序监听在8080
端口,即是从配置文件里读取的配置信息,如下:
1 2
| (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ ss -tnlp | grep python LISTEN 0 128 *:8080 *:* users:(("python",pid=22126,fd=6))
|
如果同时定义了从配置文件读取和从命令行读取,那生效的是哪个呢?做如下测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| from tornado.options import options, define from tornado.web import Application, RequestHandler from tornado.ioloop import IOLoop define("port", default=8000, type=int, help="listen port") class MainHandler(RequestHandler): def get(self, *args, **kwargs): self.write('hello') if __name__ == '__main__': options.parse_config_file('./application.conf') app = Application( [ (r'/', MainHandler) ], debug=True ) options.parse_command_line() app.listen(port=options.port, address='0.0.0.0') IOLoop.current().start()
|
程序如下运行后查看监听在哪个端口:
1 2 3 4 5 6
| (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ cat application.conf port = 8080 (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ python options_test.py --port=8005 (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ ss -tnlp | grep python LISTEN 0 128 *:8005 *:* users:(("python",pid=23810,fd=6))
|
程序监听在8005
端口,如果不在命令行传递参数,那程序会监听在哪个端口?如下:
1 2 3
| (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ python options_test.py (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ ss -tnlp | grep python) LISTEN 0 128 *:8080 *:* users:(("python",pid=24093,fd=6))
|
程序监听在了8080
这个配置在配置文件中的端口。如果把options.parse_command_line()
放在options.parse_config_file('./application.conf')
之前呢?如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| from tornado.options import options, define from tornado.web import Application, RequestHandler from tornado.ioloop import IOLoop define("port", default=8000, type=int, help="listen port") class MainHandler(RequestHandler): def get(self, *args, **kwargs): self.write('hello') if __name__ == '__main__': options.parse_command_line() options.parse_config_file('./application.conf') app = Application( [ (r'/', MainHandler) ], debug=True ) app.listen(port=options.port, address='0.0.0.0') IOLoop.current().start()
|
再运行程序试试,如下:
1 2 3 4
| (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ python options_test.py --port=8005 (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ ss -tnlp | grep python LISTEN 0 128 *:8080 *:* users:(("python",pid=8777,fd=6))
|
程序监听在8080
这个定义在配置文件中的端口,如果不传递命令行参数呢?
1 2 3 4
| gscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ python options_test.py (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ ss -tnlp | grep python LISTEN 0 128 *:8080 *:* users:(("python",pid=8937,fd=6))
|
同样监听在8080
端口,依然是配置文件中定义的参数,如果把配置文件中的信息清除呢?
1 2 3 4 5 6 7 8
| (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ echo "" > application.conf (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ python options_test.py --port=8005 (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ ss -tnlp | grep python LISTEN 0 128 *:8005 *:* users:(("python",pid=25126,fd=6)) (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ python options_test.py (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ ss -tnlp | grep python LISTEN 0 128 *:8000 *:* users:(("python",pid=25384,fd=6))
|
在上边的程序中,当把配置文件中的配置项去除后,如果命令行传递相应选项,那程序会使用命令行传递的参数,如果命令行没有传递相应的选项,那程序会使用defie
中定义的默认选项。经过以上的不断测试,可以总结出tornado
在使用配置选项时是按照如下规则:
- 配置项的读取是根据代码的定义从上往下读取,如:先定义从文件读取,再定义从命令行读取,那程序就会先从文件读取,再从命令行读取;
- 如果相同的选项在配置文件中有定义,再在命令行也传递相同的选项,那后一个读取到的选项的值会覆盖前一个值,即最后读取到的值是生效值;
- 如果配置文件和命令行都未定义选项的值,那采用
define
定义的默认值。
而在实际的编程中,从配置文件读取和从命令行读取会结合起来,并且一般会从两个地方读取配置文件,一个一般存放在/etc
目录下作为全局配置文件,另一个存放在工程的根目录下,最后再接收命令行传递的参数以便在程序调试时使用。举一个例子来说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| from tornado.options import options, define from tornado.web import Application, RequestHandler from tornado.ioloop import IOLoop define("port", default=8000, type=int, help="listen port") class MainHandler(RequestHandler): def get(self, *args, **kwargs): self.write('hello') if __name__ == '__main__': import os if os.path.exists('/etc/app.conf'): options.parse_config_file('/etc/app.conf') if os.path.exists('./application.conf'): options.parse_config_file('./application.conf') options.parse_command_line() app = Application( [ (r'/', MainHandler) ], debug=True ) app.listen(port=options.port, address='0.0.0.0') IOLoop.current().start()
|
1 2 3 4
| (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ cat /etc/app.conf port = 8888 (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ cat application.conf port = 8080
|
运行程序测试:
1 2 3 4 5 6 7
| (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ python options_test.py --port=8005 (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ ss -tnlp | grep python LISTEN 0 128 *:8005 *:* users:(("python",pid=10291,fd=6)) (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ python options_test.py (logscan-api) neal@neal-System-Product-Name:~/private/sync/temp/logscan-api/test_scripts$ ss -tnlp | grep python LISTEN 0 128 *:8080 *:* users:(("python",pid=10404,fd=6))
|
这也很好的验证了是最后读取到的那个选项生效。