使用python开发命令行程序的知识点之二

本文深入解析Python命令行程序开发的核心概念,包括全局变量的使用、长字符串表达、多线程下的日志管理、异常处理增强、模块路径获取、INI文件解析、命令行输出获取、APScheduler轮询操作、数据格式化打印等高级技巧。同时,提供了解决方案,如在Windows环境下使用特定库处理多进程日志问题,以及如何在代码中加入未处理异常处理机制。

使用python开发命令行程序的知识点之二
之前写过一个知识点, 链接是  http://www.cnblogs.com/harrychinese/archive/2011/11/03/python_console_app_dev.html , 这次补充一些.
================================
global-variables
================================
global 变量是一个模块级别的变量, 在一个方法中, 如果读取这个变量, 不需要额外做global声明, 如果要赋值, 必须做global声明.
http://stackoverflow.com/questions/423379/using-global-variables-in-a-function-other-than-the-one-that-created-them
在多个模块中,如何公用一个全局变量?
参考: http://effbot.org/pyfaq/how-do-i-share-global-variables-across-modules.htm
具体做法是: 将这个变量(比如 applicationName)放到一个类似Config模块中, 在其他模块中,要访问这个变量, 写法是:
import Config #必须是这种import写法
print(Config.applicationName)
================================
Line Continuations
http://docs.python-guide.org/en/latest/writing/style/#returning-multiple-values-from-a-function
================================
相比\拼接, 这个长字符串写法太美了
my_very_big_string = (
    "For a long time I used to go to bed early. Sometimes, "
    "when I had put out my candle, my eyes would close so quickly "
    "that I had not even time to say “I’m going to sleep.”"
)
from some.deep.module.inside.a.module import (
    a_nice_function, another_nice_function, yet_another_nice_function)
================================
logging 相关的几点
================================    
1.  和logger.error()相比, logger.exception()会打印出traceback
2.  Windows下, 多进程/线程程序如使用标准库 RotatingFileHandler, 在换文件的时候很可能报错WindowsError: [Error 32],  之后的log将写不记录下来. 可以使用ConcurrentLogHandler库中的ConcurrentRotatingFileHandler类,  该库下载地址 http://pypi.python.org/pypi/ConcurrentLogHandler/0.8.4.
    如果要在Windows使用该库, 需要 pywin32 库.
    另外, 0.8.4 版的 cloghandler.py 在 Line 194 行有个bug, 应该在stream.flush()之前, 检查一下stream是否closed.
    if self.stream.closed==False:
        self.stream.flush()
3.  Java 使用 Log4j, 可以在 log4j.properties 配置文件中来控制 log 的输出. Python的 logging 模块也可这样, 示例代码见 http://pypi.python.org/pypi/ConcurrentLogHandler/0.8.4
================================    
Uncaught exception
为程序加上unhandled exception
================================    
#module name:uncaught_exception.py
import sys
import logging
import helper
logger=logging.getLogger(__name__)
helper.caw_logging.configureLogger(logger)
def my_excepthook(type, value, traceback):
    msg= 'Uncaught exception: %s, %s'%( type, value)
    logger.exception(msg)
sys.excepthook = my_excepthook
在我们的程序中, 只需import uncaught_exception模块, 就能增加一个 uncaught exception handler.
================================    
比如主程序为 application.py, 如何获取这个py的目录名.
方法: 专门弄一个assembly_path.py, 放在和application.py同一个目录下
================================
module name: assembly_path.py
import inspect
def getCurrentFileName():
    '''
    return the full file name of assembly_path.py
    '''
    return inspect.getfile(inspect.currentframe())
def getCurrentPath():
    '''
    return the full path of assembly_path.py
    '''
    fullFileName=getCurrentFileName()
    (dirName, fileName) = os.path.split(fullFileName)
    return os.path.normpath(dirName)
def getCurrentPath_2():
    return os.path.dirname(os.path.abspath(__file__))
================================    
解析ini文件    
================================
[basic]
#db url, like sqlite:///c://caw.sqlite.db
sqlalchemy.url=mysql://root:root123@localhost/caw
[additional]
job_worker_conn_pool_size=10
下面是一个解析示例, 可以为解析器设置defaults, 每个default config item的value必须是一个字符串.
我原来使用了一个数值, 结果报类型异常, 提示很隐晦, 好久才搞明白应使用字符串.  
#py code
defaultConfigItems={
                    'job_worker_conn_pool_size':'15'
                    }
parser = SafeConfigParser(defaults=defaultConfigItems)
parser.read(self.iniFile)
self.sqlalchemy_url=parser.get('basic', 'sqlalchemy.url')
self.job_worker_conn_pool_size=parser.get('additional', 'job_worker_conn_pool_size')
================================    
怎样获取comandline 程序的输出
================================
首先调用launchCmdLine()启动一个进程, 拿到对应的process对象, 然后调用waitResultOfCmdProcess()知道该进程结束, 并获取exit code和output输出和error输出.
def launchCmdLine(*popenargs, **kwargs):
    '''
    run command line, return pid, exitcode, output, error message together
    '''
    #capture cmd output
    #For windows, shell should be False, but there is a bug  http://bugs.python.org/issue8224, we should set shell=True
    #For Linux, shell=True
    if isWindows():
        shellValue=True
    else:
        shellValue=True
    process = subprocess.Popen(shell=shellValue, stdout=subprocess.PIPE, stderr=subprocess.PIPE, *popenargs, **kwargs)
    return process
def waitResultOfCmdProcess(process):
    '''
    check process result, return exitcode, output, error message together
    '''
    output, error = process.communicate()
    exitcode = process.wait()
    return (exitcode, output, error)
================================    
使用 apscheduler.scheduler.add_interval_job() 来做轮询操作
================================
apscheduler.scheduler.add_interval_job()会启动另外的线程, 比较适合于频繁启动长任务. 示例:
from apscheduler.scheduler import Scheduler
def scanMisfire():
    pass
if __name__=="__main__":   
    misfireScheduler=Scheduler()
    sleep_seconds=120  # 2 minute
    misfireScheduler.add_interval_job(scanMisfire, seconds=sleep_seconds)
    misfireScheduler.start()    
    #dead loop to prevent program exiting.
    while True:
        time.sleep(9999)
    misfireScheduler.shutdown()
================================
格式化打印db query结果集
================================
Oracle sqlplus 有格式化输出结果集的功能, 如果我们程序也需要有类似的功能, 可以使用prettytable 和 texttable 包.  当然, 数据不能包含汉字, 否则格式就乱掉. 另外, 如果数据包含回车换行, texttable会好一些.
================================    
Add code in PYTHONPATH temporarily
================================
对于一个多模块的程序, 没有将code放在python的site-packages目录中, 运行程序往往会报加载有问题. 解决方法是将程序代码放到PYTHONPATH环境变量中, 当然也可以写个batch脚本, 临时性地将code加到PYTHONPATH环境变量中
windows下,
SET SAVE=%PYTHONPATH%
SET PYTHONPATH=D://trunk/workspace/proj1/src
C:\pythonenv\python27_flask\Scripts\python.exe D:\trunk\workspace\proj1\src\myapp.py
SET PYTHONPATH=%SAVE%

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值