init与clinit的区别

今天在看深入Java虚拟机的class文件结构时,看到了这么一句话,

可能出现在class文件中的两种编译器产生的方法是:实例初始化方法(名为<init>)和类与接口初始化方法(名为<clinit>)。

 

这两种方法有什么区别呢?

首先:这两个方法一个是虚拟机在装载一个类初始化的时候调用的(clinit)。另一个是在类实例化时调用的(init)

 

首先说说类的初始化:

在Java代码中,一个正确的初始值是通过类变量初始化语句或者静态初始化语句给出的。一个类变量初始化语句是

变量声明后的等号和表达式:

Java代码  收藏代码
  1. class Example {
  2.        static int size = 3 * (int) (Math.random() * 5.0);
  3. }

 

静态初始化语句是一个以static开头的语句块:

Java代码  收藏代码
  1. class Example{
  2.      static int size;
  3.      static {
  4.            size = 3 * (int) (Math.random() * 5.0);
  5.      }
  6. }

所有的类变量初始化语句和类型的静态初始化语句都被Java编译器收集到了一起,放在一个特殊的方法中。这个方法就是<clinit>

 

我们在来看看<init>这个方法:

<init>方法是在一个类进行对象实例化时调用的。实例化一个类有四种途径:调用new操作符;调用Class或java.lang.reflect.Constructor对象的newInstance()方法;调用任何现有对象的clone()方法;通过java.io.ObjectInputStream类的getObject()方法反序列化。

 

Java编译器会为它的每一个类都至少生成一个实例初始化方法。在Class文件中,被称为”<init>”

 

现在知道了吧, 一个是用于初始化静态的类变量, 一个是初始化实例变量!

python爬虫–基本适用所有情况

import urllib, urllib2, cookielib

def crawl():

parameters = {‘p1′:”,’p2’:”}

url = ‘http://www.website.com’

#设置get参数以下

#parameters[‘p1’] = ‘p1value’

query_data = urllib.urlencode(parameters)

request_data = urllib2.Request(url,query_data)

#创建cookie管理器

cj = cookielib.CookieJar()

opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
opener.addheaders = [(‘User-Agent’,’Robot Client v1.0′),(‘Refferer’,’http://www.anva.org.cn’)]
#response = urllib2.urlopen(request_data)
response = opener.open(request_data)
pageContent = response.read().strip()

 

 

使用python的logging模块

一、从一个使用场景开始

 

开发一个日志系统, 既要把日志输出到控制台, 还要写入日志文件

 

Python代码  收藏代码
  1. import logging
  2. # 创建一个logger
  3. logger = logging.getLogger(‘mylogger’)
  4. logger.setLevel(logging.DEBUG)
  5. # 创建一个handler,用于写入日志文件
  6. fh = logging.FileHandler(‘test.log’)
  7. fh.setLevel(logging.DEBUG)
  8. # 再创建一个handler,用于输出到控制台
  9. ch = logging.StreamHandler()
  10. ch.setLevel(logging.DEBUG)
  11. # 定义handler的输出格式
  12. formatter = logging.Formatter(‘%(asctime)s – %(name)s – %(levelname)s – %(message)s’)
  13. fh.setFormatter(formatter)
  14. ch.setFormatter(formatter)
  15. # 给logger添加handler
  16. logger.addHandler(fh)
  17. logger.addHandler(ch)
  18. # 记录一条日志
  19. logger.info(‘foorbar’)

 

 

运行后, 在控制台和日志文件都有一条日志:

 

Java代码  收藏代码
  1. 2011-08-31 19:18:29,816 – mylogger – INFO – foorbar

 

 

二、logging模块的API

 

结合上面的例子,我们说下几个最常使用的API

logging.getLogger([name])返回一个logger实例,如果没有指定name,返回root logger。只要name相同,返回的logger实例都是同一个而且只有一个,即name和logger实例是一一对应的。这意味着,无需把logger实例在各个模块中传递。只要知道name,就能得到同一个logger实例
Logger.setLevel(lvl)设置logger的level, level有以下几个级别:

NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL
如果把looger的级别设置为INFO, 那么小于INFO级别的日志都不输出, 大于等于INFO级别的日志都输出

Python代码  收藏代码
  1. logger.debug(“foobar”)    # 不输出
  2. logger.info(“foobar”)        # 输出
  3. logger.warning(“foobar”) # 输出
  4. logger.error(“foobar”)      # 输出
  5. logger.critical(“foobar”)    # 输出

Logger.addHandler(hdlr)logger可以雇佣handler来帮它处理日志, handler主要有以下几种:StreamHandler: 输出到控制台FileHandler:   输出到文件handler还可以设置自己的level以及输出格式。
logging.basicConfig([**kwargs])* 这个函数用来配置root logger, 为root logger创建一个StreamHandler,   设置默认的格式。* 这些函数: logging.debug()、logging.info()、logging.warning()、   logging.error()、logging.critical() 如果调用的时候发现root logger没有任何   handler, 会自动调用basicConfig添加一个handler* 如果root logger已有handler, 这个函数不做任何事情
使用basicConfig来配置root logger的输出格式和level:

Python代码  收藏代码
  1. import logging
  2. logging.basicConfig(format=’%(levelname)s:%(message)s’, level=logging.DEBUG)
  3. logging.debug(‘This message should appear on the console’)

三、关于root logger以及logger的父子关系
前面多次提到root logger, 实际上logger实例之间还有父子关系, root logger就是处于最顶层的logger, 它是所有logger的祖先。如下图:root logger是默认的logger如果不创建logger实例, 直接调用logging.debug()、logging.info()logging.warning()、logging.error()、logging.critical()这些函数,那么使用的logger就是 root logger, 它可以自动创建,也是单实例的。
如何得到root logger通过logging.getLogger()或者logging.getLogger(“”)得到root logger实例。
默认的levelroot logger默认的level是logging.WARNING
如何表示父子关系logger的name的命名方式可以表示logger之间的父子关系. 比如:parent_logger = logging.getLogger(‘foo’)child_logger = logging.getLogger(‘foo.bar’)
什么是effective levellogger有一个概念,叫effective level。 如果一个logger没有显示地设置level,那么它就用父亲的level。如果父亲也没有显示地设置level, 就用父亲的父亲的level,以此推….最后到达root logger,一定设置过level。默认为logging.WARNINGchild loggers得到消息后,既把消息分发给它的handler处理,也会传递给所有祖先logger处理,
来看一个例子

Python代码  收藏代码
  1. import logging
  2. # 设置root logger
  3. r = logging.getLogger()
  4. ch = logging.StreamHandler()
  5. ch.setLevel(logging.DEBUG)
  6. formatter = logging.Formatter(‘%(asctime)s – %(levelname)s – %(message)s’)
  7. ch.setFormatter(formatter)
  8. r.addHandler(ch)
  9. # 创建一个logger作为父亲
  10. p = logging.getLogger(‘foo’)
  11. p.setLevel(logging.DEBUG)
  12. ch = logging.StreamHandler()
  13. ch.setLevel(logging.DEBUG)
  14. formatter = logging.Formatter(‘%(asctime)s – %(message)s’)
  15. ch.setFormatter(formatter)
  16. p.addHandler(ch)
  17. # 创建一个孩子logger
  18. c = logging.getLogger(‘foo.bar’)
  19. c.debug(‘foo’)

输出如下:

Python代码  收藏代码
  1. 2011-08-31 21:04:29,893 – foo
  2. 2011-08-31 21:04:29,893 – DEBUG – foo

可见, 孩子logger没有任何handler,所以对消息不做处理。但是它把消息转发给了它的父亲以及root logger。最后输出两条日志。

from: http://kenby.iteye.com/blog/1162698

配置VIM实现新建c/c++文件,自动插入注释和文件头

编辑~/.vimrc 加入以下代码

 1 autocmd BufNewFile *.[ch],*.hpp,*.cpp exec “:call SetTitle()”
2
3 “加入注释
4 func SetComment()
5     call setline(1,”/*===============================================================”)
6     call append(line(“.”),   “*   Copyright (C) “.strftime(“%Y”).” All rights reserved.”)
7     call append(line(“.”)+1, “*   “)
8     call append(line(“.”)+2, “*   文件名称:”.expand(“%:t”))
9     call append(line(“.”)+3, “*   创 建 者:蒋浩”)
10     call append(line(“.”)+4, “*   创建日期:”.strftime(“%Y年%m月%d日”))
11     call append(line(“.”)+5, “*   描    述:”)
12     call append(line(“.”)+6, “*”)
13     call append(line(“.”)+7, “*   更新日志:”)
14     call append(line(“.”)+8, “*”)
15     call append(line(“.”)+9, “================================================================*/”)
16 endfunc
17
18 “定义函数SetTitle,自动插入文件头
19 func SetTitle()
20     call SetComment()
21     if expand(“%:e”) == ‘hpp’
22  call append(line(“.”)+10, “#ifndef _”.toupper(expand(“%:t:r”)).”_H”)
23  call append(line(“.”)+11, “#define _”.toupper(expand(“%:t:r”)).”_H”)
24  call append(line(“.”)+12, “#ifdef __cplusplus”)
25  call append(line(“.”)+13, “extern \”C\””)
26  call append(line(“.”)+14, “{“)
27  call append(line(“.”)+15, “#endif”)
28  call append(line(“.”)+16, “”)
29  call append(line(“.”)+17, “#ifdef __cplusplus”)
30  call append(line(“.”)+18, “}”)
31  call append(line(“.”)+19, “#endif”)
32  call append(line(“.”)+20, “#endif //”.toupper(expand(“%:t:r”)).”_H”)
33     elseif expand(“%:e”) == ‘h’
34  call append(line(“.”)+10, “#pragma once”)
35     elseif &filetype == ‘c’
36  call append(line(“.”)+10,”#include \””.expand(“%:t:r”).”.h\””)
37     elseif &filetype == ‘cpp’
38  call append(line(“.”)+10, “#include \””.expand(“%:t:r”).”.h\””)
39     endif
40 endfunc
41

Python 发送邮件

#!/usr/bin/python
#-*-coding:utf8-*-

import smtplib, os
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders

def send():
send_mail(‘From .. Address’, [‘to .. Address’], ‘mail title’,’mail content’, [‘sendMail.py’], ‘mail server’)
def send_mail(send_from, send_to, subject, text, files=[], server=”localhost”):
assert type(send_to)==list
assert type(files)==list

msg = MIMEMultipart()
msg[‘From’] = send_from
msg[‘To’] = COMMASPACE.join(send_to)
msg[‘Date’] = formatdate(localtime=True)
msg[‘Subject’] = subject

msg.attach( MIMEText(text) )

for f in files:
part = MIMEBase(‘application’, “octet-stream”)
part.set_payload( open(f,”rb”).read() )
Encoders.encode_base64(part)
part.add_header(‘Content-Disposition’, ‘attachment; filename=”%s”‘ % os.path.basename(f))
msg.attach(part)

smtp = smtplib.SMTP(server)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()

#— — —-
send()

目前流行的十大手机病毒家族

1. FakeInst

伪装成安装包诱惑用户安装,后台发送扣费短信,定制sp业务,给用户造成经济损失。

 

 

2. feejar

利用情色内容引诱用户安装,启动后私自下载其他安装包,并发送短信订阅服务,存在恶意扣费行为。

 

 

3. FakeOpera

伪装成安装或更新应用欺骗用户安装,病毒激活后后台发送扣费短信,定制sp业务,给用户造成经济损失

 

 

4. Keji

后门程序,后台自动下载恶意应用

 

 

5. GinMaster

样本重打包为游戏兔子等工具诱惑用户安装,样本激活后会静默下载推广应用,造成用户资费消耗,并可能下载新恶意应用对用户造成更大的破坏。

 

 

6. m933

样本伪装成系统应用或者系统更新,用户中招后病毒会恶意下载新应用消耗用户流量。

 

 

7. Kmin

该病毒伪装为kmLaucher 桌面管理程序,病毒激活后后台发送扣费短信,定制sp业务,给用户。造成经济损失。

 

 

8. i22hk

样本重打包为XXX卫士、傲游浏览器、人人网客户端、酷我音乐盒等30几款知名应用,病毒激活后窃取用户隐私信息,下载新应用。

 

 

9. Elpso

伪装成色情应用,用户安装后静默发送扣费短信拦截短信给用户造成经济损失

 

 

10. Popsg

病毒伪装成偷偷去约会、池塘钓鱼、塔防游戏阵型王道、武装战机、MyFirstColoringApp等十几款应用,病毒激活后会在其他应用(如微信、uc浏览器、qq浏览器等)中弹出广告。

 

 

MMarketPay.A

, New Android Malware Found in the Wild – See more at: http://blog.trustgo.com/mmarketpay/#sthash.heuNDoSF.dpuf

SUMMARY

 

On the 4th of July 2012, we uncovered a new malware that can download paid apps and contents from China Mobile’s Mobile Market. It placed orders automatically on behalf of users and could cause unexpected high phone bills. TrustGo Security Labs named it as: Trojan!MMarketPay.A@Android.

MMarketPay.A may arrive as repackaged applications with the following package names:

  • com.mediawoz.goweather
  • com.mediawoz.gotq
  • com.mediawoz.gotq1
  • cn.itkt.travelskygo
  • cn.itkt.travelsky
  • com.funinhand.weibo
  • sina.mobile.tianqitong
  • com.estrongs.android.pop

This virus is already found in following 9 China markets. More than 100,000 devices have been infected.

HOW IT WORKS

 

Mobile Market (http://mm.10086.cn/) is an Android Market hosted by China Mobile, one of the largest wireless providers on the planet. It hosts both free and paid applications and multimedia contents. Its payment workflow for paid application is as following:

  1. Customers login at M-Market website (http://mm.10086.cn/). No login required if customer use If you are using CMWAP as Access Point.
  2. M-Market will send a verification code to you via SMS if customer purchased paid apps or contents.
  3. Customers receive the verification code and input it to M-Market for verification
  4. Once the verification completed, the market will download apps automatically. China Mobile will add this order in customers’ phone bill.

MMarketPay.A can place orders via M-Market payment system automatically:

  1. Change the APN to CMWAP, so that it can login MMarket automatically.
  2. Find paid application and simulate the click action in background.
  3. Intercept the received SMS messages and collect verification code sent by M-Market.
  4. If CAPTCHA image is invoked, it will post the image to remote server for analyzing the verification code.
  5. Post the verification code to M-Market website.
  6. Download the application and customers get charged.

Following screenshot of malicious code shows the whole auto payment process.

Besides paid apps, M-Market also offers paid video contents. MMarketPay.A can also search, play and pay for the paid video contents on M-Market. Following piece of code shows the paid video auto play.

CONCLUSION

 

In summary, this sophisticated new malware could cause unexpected high phone bills. TrustGo recommends customers only download apps from trusted app stores and download a mobile security app which can scan malware in real-time.

– See more at: http://blog.trustgo.com/mmarketpay/#sthash.heuNDoSF.dpuf

破解android锁屏密码 [转]

android的锁屏密码大家应该都不陌生,本文所讲的即是对此密码的破解方法。

适合平台:android

所需条件:已root,打开USB调试

意义:几乎没用。

android的锁屏密码是连接一个3*3个点的图上面的点,要求如下:

至少4个点;

最多9个点;

无重复。

实际上,android系统将这9个点分别对应于0-8这9个数字,然后将连接的路径转换为这9个数字,并对其进行SHA1加密然后存储于一个文件中。数字对应如下:

0 1 2

3 4 5

6 7 8

比如一个大Z字型的密码,就是0124678,然后将这几个数字作为一个进行SHA1运算,再以16进制的形式存入/data/system/gesture.key文件当中。

破解方法1:

因为没有设置该密码手机将不会有这个文件的,而且如果没有这个文件,也不会要求输入锁屏密码。

所以方法很简单:adb连接上手机,删除/data/system/gesture.key文件。如下图:



破解方法2:

如果不想删除该文件,只是想知道密码的话,则可以读取该文件的数字,然后用暴力破解的方式进行猜解。由于密码是4至9位长度的数字(0-8),并且没有重复,再去除像0213这种不合法的密码(先连了首尾两个再连中间的点,这样的密码不可能存在。像路径为0213或0842等),生成密码词典并进行猜解,在电脑上几乎是秒破的。

该文件直接打开是乱码的,需要以16进制来查看。如下图:

以16进制读取该文件并转成字符串,然后生成由0至8组成的4至8位的数组,进行SHA1加密运算,并与上面的字符串对比。下面是我用电脑进行暴力猜解所生成的密码个数,以及最坏情况下所用时间:



共耗时0.975254947秒

复制代码

上面的密码个数不一定是最优解的个数,但应该没有漏了。破解android上这样一个锁屏密码,在我的G47(I5 CPU)电脑上所用时间约1秒。

在我的手机上进行破解的时间有点长,如下图是最坏情况下的破解结果:



由于猜解密码需要root权限,并且打开Adb调试,所以实际上此功能并没有多大用处,最多就是我借做android开发的朋友的手机(他们的都ROOT过并打开了USB调试)来看看他们的密码是什么,当然为能还需要他们先解锁下= =!。所以此文仅为技术交流。
原文转自:枫叶博客www.fengye123.com

Python模块学习——optparse

Python 有两个内建的模块用于处理命令行参数:

一个是 getopt,《Deep in python》一书中也有提到,只能简单处理 命令行参数;

另一个是 optparse,它功能强大,而且易于使用,可以方便地生成标准的、符合Unix/Posix 规范的命令行说明。

示例

下面是一个使用 optparse 的简单示例:

Python代码
  1. from optparse import OptionParser
  2. […]
  3. parser = OptionParser()
  4. parser.add_option(“-f”, “–file”, dest=”filename”,
  5.                   help=”write report to FILE”, metavar=”FILE”)
  6. parser.add_option(“-q”, “–quiet”,
  7.                   action=”store_false”, dest=”verbose”, default=True,
  8.                   help=”don’t print status messages to stdout”)
  9. (options, args) = parser.parse_args()

现在,妳就可以在命令行下输入:

Python代码
  1. <yourscript> –file=outfile -q
  2. <yourscript> -f outfile –quiet
  3. <yourscript> –quiet –file outfile
  4. <yourscript> -q -foutfile
  5. <yourscript> -qfoutfile

上面这些命令是相同效果的。除此之外, optparse 还为我们自动生成命令行的帮助信息:

Python代码
  1. <yourscript> -h
  2. <yourscript> –help

输出:

Python代码
  1. usage: <yourscript> [options]
  2. options:
  3.   -h, –help            show this help message and exit
  4.   -f FILE, –file=FILE  write report to FILE
  5.   -q, –quiet           don’t print status messages to stdout

 

简单流程

首先,必须 import OptionParser 类,创建一个 OptionParser 对象:

Python代码
  1. from optparse import OptionParser
  2. […]
  3. parser = OptionParser()

然后,使用 add_option 来定义命令行参数:

Python代码
  1. parser.add_option(opt_str, …,
  2.                   attr=value, …)

每个命令行参数就是由参数名字符串和参数属性组成的。如 -f 或者 –file 分别是长短参数名:

Python代码
  1. parser.add_option(“-f”, “–file”, …)

最后,一旦你已经定义好了所有的命令行参数,调用 parse_args() 来解析程序的命令行:

Python代码
  1. (options, args) = parser.parse_args()

注: 你也可以传递一个命令行参数列表到 parse_args();否则,默认使用 sys.argv[:1]。

parse_args() 返回的两个值:

  • options,它是一个对象(optpars.Values),保存有命令行参数值。只要知道命令行参数名,如 file,就可以访问其对应的值: options.file 。
  • args,它是一个由 positional arguments 组成的列表。

Actions

action 是 parse_args() 方法的参数之一,它指示 optparse 当解析到一个命令行参数时该如何处理。actions 有一组固定的值可供选择,默认是’store ‘,表示将命令行参数值保存在 options 对象里。

示例

Python代码
  1. parser.add_option(“-f”, “–file”,
  2.                   action=”store”, type=”string”, dest=”filename”)
  3. args = [“-f”, “foo.txt”]
  4. (options, args) = parser.parse_args(args)
  5. print options.filename

最后将会打印出 “foo.txt”。

当 optparse 解析到’-f’,会继续解析后面的’foo.txt’,然后将’foo.txt’保存到 options.filename 里。当调用 parser.args() 后,options.filename 的值就为’foo.txt’。

你也可以指定 add_option() 方法中 type 参数为其它值,如 int 或者 float 等等:

Python代码
  1. parser.add_option(“-n”, type=”int”, dest=”num”)

默认地,type 为’string’。也正如上面所示,长参数名也是可选的。其实,dest 参数也是可选的。如果没有指定 dest 参数,将用命令行的参数名来对 options 对象的值进行存取。

store 也有其它的两种形式: store_true 和 store_false ,用于处理带命令行参数后面不 带值的情况。如 -v,-q 等命令行参数:

Python代码
  1. parser.add_option(“-v”, action=”store_true”, dest=”verbose”)
  2. parser.add_option(“-q”, action=”store_false”, dest=”verbose”)

这样的话,当解析到 ‘-v’,options.verbose 将被赋予 True 值,反之,解析到 ‘-q’,会被赋予 False 值。

其它的 actions 值还有:

store_const 、append 、count 、callback 。

 

默认值

parse_args() 方法提供了一个 default 参数用于设置默认值。如:

Python代码
  1. parser.add_option(“-f”,”–file”, action=”store”, dest=”filename”, default=”foo.txt”)
  2. parser.add_option(“-v”, action=”store_true”, dest=”verbose”, default=True)

又或者使用 set_defaults():

Python代码
  1. parser.set_defaults(filename=”foo.txt”,verbose=True)
  2. parser.add_option(…)
  3. (options, args) = parser.parse_args()

 

生成程序帮助

optparse 另一个方便的功能是自动生成程序的帮助信息。你只需要为 add_option() 方法的 help 参数指定帮助信息文本:

Python代码
  1. usage = “usage: %prog [options] arg1 arg2”
  2. parser = OptionParser(usage=usage)
  3. parser.add_option(“-v”, “–verbose”,
  4.                   action=”store_true”, dest=”verbose”, default=True,
  5.                   help=”make lots of noise [default]”)
  6. parser.add_option(“-q”, “–quiet”,
  7.                   action=”store_false”, dest=”verbose”,
  8.                   help=”be vewwy quiet (I’m hunting wabbits)”)
  9. parser.add_option(“-f”, “–filename”,
  10.                   metavar=”FILE”, help=”write output to FILE”),
  11. parser.add_option(“-m”, “–mode”,
  12.                   default=”intermediate”,
  13.               help=”interaction mode: novice, intermediate, “
  14.                    “or expert [default: %default]”)

当 optparse 解析到 -h 或者 –help 命令行参数时,会调用 parser.print_help() 打印程序的帮助信息:

Python代码
  1. usage: <yourscript> [options] arg1 arg2
  2. options:
  3.   -h, –help            show this help message and exit
  4.   -v, –verbose         make lots of noise [default]
  5.   -q, –quiet           be vewwy quiet (I’m hunting wabbits)
  6.   -f FILE, –filename=FILE
  7.                         write output to FILE
  8.   -m MODE, –mode=MODE  interaction mode: novice, intermediate, or
  9.                         expert [default: intermediate]

注意: 打印出帮助信息后,optparse 将会退出,不再解析其它的命令行参数。

以上面的例子来一步步解释如何生成帮助信息:

  • 自定义的程序使用方法信息(usage message):
    Python代码
    1. usage = “usage: %prog [options] arg1 arg2”

    这行信息会优先打印在程序的选项信息前。当中的 %prog,optparse 会以当前程序名的字符串来替代:如 os.path.basename.(sys.argv[0])。

    如果用户没有提供自定义的使用方法信息,optparse 会默认使用: “usage: %prog [options]”。

  • 用户在定义命令行参数的帮助信息时,不用担心换行带来的问题,optparse 会处理好这一切。
  • 设置 add_option 方法中的 metavar 参数,有助于提醒用户,该命令行参数所期待的参数,如 metavar=“mode”:
    Python代码
    1. -m MODE, –mode=MODE

    注意: metavar 参数中的字符串会自动变为大写。

  • 在 help 参数的帮助信息里使用 %default 可以插入该命令行参数的默认值。

如果程序有很多的命令行参数,你可能想为他们进行分组,这时可以使用 OptonGroup:

Python代码
  1. group = OptionGroup(parser, “Dangerous Options”,
  2.                     “Caution: use these options at your own risk.  “
  3.                     “It is believed that some of them bite.”)
  4. group.add_option(“-g”, action=”store_true”, help=”Group option.”)
  5. parser.add_option_group(group)

下面是将会打印出来的帮助信息:

Python代码
  1. usage:  [options] arg1 arg2
  2. options:
  3.   -h, –help           show this help message and exit
  4.   -v, –verbose        make lots of noise [default]
  5.   -q, –quiet          be vewwy quiet (I’m hunting wabbits)
  6.   -fFILE, –file=FILE  write output to FILE
  7.   -mMODE, –mode=MODE  interaction mode: one of ‘novice’, ‘intermediate’
  8.                        [default], ‘expert’
  9.   Dangerous Options:
  10.     Caution: use of these options is at your own risk.  It is believed that
  11.     some of them bite.
  12.     -g                 Group option.

 

显示程序版本

象 usage message 一样,你可以在创建 OptionParser 对象时,指定其 version 参数,用于显示当前程序的版本信息:

Python代码
  1. parser = OptionParser(usage=”%prog [-f] [-q]”, version=”%prog 1.0″)

这样,optparse 就会自动解释 –version 命令行参数:

Python代码
  1. $ /usr/bin/foo –version
  2. foo 1.0

 

处理异常

包括程序异常和用户异常。这里主要讨论的是用户异常,是指因用户输入无效的、不完整的命令行参数而引发的异常。optparse 可以自动探测并处理一些用户异常:

Python代码
  1. $ /usr/bin/foo -n 4x
  2. usage: foo [options]
  3. foo: error: option -n: invalid integer value: ‘4x’
  4. $ /usr/bin/foo -n
  5. usage: foo [options]
  6. foo: error: -n option requires an argument

用户也可以使用 parser.error() 方法来自定义部分异常的处理:

Python代码
  1. (options, args) = parser.parse_args()
  2. […]
  3. if options.a and options.b:
  4.     parser.error(“options -a and -b are mutually exclusive”)

上面的例子,当 -b 和 -b 命令行参数同时存在时,会打印出“options -a and -b are mutually exclusive“,以警告用户。

如果以上的异常处理方法还不能满足要求,你可能需要继承 OptionParser 类,并重载 exit() 和 erro() 方法。

 

完整的程序例子

Python代码
  1. from optparse import OptionParser
  2. […]
  3. def main():
  4.     usage = “usage: %prog [options] arg”
  5.     parser = OptionParser(usage)
  6.     parser.add_option(“-f”, “–file”, dest=”filename”,
  7.                       help=”read data from FILENAME”)
  8.     parser.add_option(“-v”, “–verbose”,
  9.                       action=”store_true”, dest=”verbose”)
  10.     parser.add_option(“-q”, “–quiet”,
  11.                       action=”store_false”, dest=”verbose”)
  12.     […]
  13.     (options, args) = parser.parse_args()
  14.     if len(args) != 1:
  15.         parser.error(“incorrect number of arguments”)
  16.     if options.verbose:
  17.         print “reading %s…” % options.filename
  18.     […]
  19. if __name__ == “__main__”:
  20.     main()

参考资料