python argparse 要点

写个需要参数的python脚本时,这个argparse模块就是相当顺手的,已默认支持常用的参数书写形式。

比如:

parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('--foo')
parser.add_argument('-b','--bar')
# 那么下面的结果都是一样
# PROG --foo 2 --bar 3
parser.parse_args(['--foo','2', '--bar', '3'])
# PROG --fo 2 -b 3
parser.parse_args(['--fo','2', '-b', '3']) # 支持长参数只书写前面能区分出的部分即可,ArgumentParser的参数allow_abbrev=False可以关闭这个特性
# PROG --fo=2 -b=3
parser.parse_args(['--fo=2', '-b=3']) # 长短参数都可以使用等于号形式赋值
# PROG --foo=2 -b3
parser.parse_args(['--foo=2', '-b3']) # 短参数还支持连写形式

继续阅读python argparse 要点

python logging 要点

print大法固然随手就能方便写出来,但是某些情况还是用的不爽,需要更为专业的日志记录,那就看下python内置的logging模块吧。另外还有google出品的glog等第三方的日志模块,本问不涉及了。

一些基本概念

logger 记录器,记录器可以指定一个或多个handler处理器,以便同时记录到多个位置或者别的什么的区别记录。
handler 实际的处理器,logging模块里的日志最终处理者。
filter 过滤器,logger和handler上都可以指定filter。
formatter 格式化器,这个概念简单,就是决定最终输出格式的,关联与handler上。
loggers树 所有的loggers被整合成一棵以root为根的树,以定义时的名字为信息构建这个树,定义时以.符号分级。另外,某logger生成的record记录完后会自动向其父级logger传播,一直传播到root节点或遇到某级配置propagate = False的logger。
root根logger 默认会被创建的记录器。直接使用logging.warn()模块级日志函数使用的记录器就是它, basicConfig() 的设置也是针对它的, logging.getLogger() 不制定名字获得的logger也是它。

一些使用建议

配置方法

logging以子模块logging.config支持下面三种配置方式:

fileConfig 文件形式配置,文件格式就是configparser所支持的格式,基本就是ini格式。
dictConfig 直接用一个dict字典描述的配置信息,除了方便代码中直接写dict配置外,也方便导入以其他诸如json、yaml等配置文件描述的配置。
listen 启动一个socket server监听配置信息。
*basicConfig 这个basicConfig并不属于logging.config,但它可以配置最顶级的root节点。
*代码配置 对啊,我们当让可以直接在代码中创建logging中的各种对象添加到loggers树中,也可以用代码再对树中的各项予以再配置。

一些使用tips

getLogger(__name__)

使用模块方法logging.getLogger方法来获取或创建logger,多次以同一名称调用该方法获得的logger是同一个对象,不用担心重复或重新创建,安心使用。一般直接用模块名称__name__创建模块内使用的logger。

msg延迟格式化

尽量使用logging.info("info: %s",param)的方式而不是已格式化的字符串logging.info("info: {}".format(param)),因为msg可能被配置过滤掉无需输出了啊。

已内置的Handlers

FileHandler 基本的文件日志处理器。
WatchedFileHandler 它会监视文件,如果日志文件被其他程序改变,会自动关闭并重新打开文件。
RotatingFileHandler,
TimedRotatingFileHandler
以一组序列的文件名来循环记录日志,以文件大小或者时间间隔为限。
SocketHandler,
DatagramHandler
分别用TCP和UDP方式发布日志。
SMTPHandler,HTTPHandler 以SMTP和HTTP方法发布日志。
MemoryHandler 先缓存日志在内容中,后再flush到目标handler上。
NullHandler no-op。
SysLogHandler,
NTEventLogHandler
发布日志到unix syslog和NT event上。
StreamHandler 支持stdout stderr,以及其他支持write()flush()方法的所有文件或类文件对象。

python的单元测试和文档测试模块

unittest模块

用法炒鸡简单,基本用法如下

#!/usr/bin/env python  
#encoding: utf-8  
import unittest

def sum(x, y):
    return x+y

class TestFunc(unittest.TestCase):
    def setUp(self):
        pass
    def tearDown(self):  
        pass

    def test_sum_3_4(self):
        self.assertEqual(sum(3,4), 7)

    def test_sum_3_4_NE6(self):
        self.assertNotEqual(sum(3,4), 6)

    @unittest.expectedFailure
    def test_sum_3_4_EF(self):
        self.assertEqual(sum(3,4), 6)


if __name__ == '__main__':
    unittest.main()
    1. 首先引入 unittest 模块
    2. 定义 TestCase 类,类的 setUp 和 tearDown 函数按需使用,比如测试的一个类的话,在 setUp 中可实例化出一个被测类供测试函数使用,然后再写一堆 test_xxx 函数即可。
    3. 最后,main 模块中使用 unittest.main() 启动整个测试即可。
    4. 自动寻找文件夹中所有的单元测试文件并执行它python -m unittest discover -s ut_dir

doctest模块

doctest模块主要用于对文档字符串写的用法示例进行测试。

怎么写可以进行doctest的示例代码呢?直接实例吧

#!/usr/bin/env python  
#encoding: utf-8  

def sum( x, y):
    """sum function.
    
    Example:
    >>> sum(3,4)
    7
    """
    return x+y

if __name__ == '__main__':
    import doctest
    doctest.testmod()

直接运行这个py文件,嗯,啥结果也没有看见,那就对了,说明doctest通过了。doctest默认是不显示任何结果的,除非使用-v参数:python myfile.py -v 就可以看到doctest执行过程和结果了。

另外,doctest还提供了unittest API以方便unittest直接把doctest一块执行了。
只需要再测试模块中定义个`load_tests()`函数即可

def load_tests(loader, tests, ignore):
    tests.addTests(doctest.DocTestSuite())
    return tests

这般以后,unittest.main()会把doctest也一块给做了。

python正则表达式总结

match/search会缓存最近的对象

re.compile返回的是一个正则表达式对象。
下面两种方式等效,在使用正则较少的情况下不用太担心直接使用re.match的性能问题,因为match/search会缓存最近的对象。

pat = re.compile(pattern)
result = pat.match(string)
# is equivalent to
result = re.match(pattern, string)

re对象的方法

Method/Attribute Purpose
match() Determine if the RE matches at the beginning of the string.
search() Scan through a string, looking for any location where this RE matches.
findall() Find all substrings where the RE matches, and returns them as a list.
finditer() Find all substrings where the RE matches, and returns them as an iterator.

matchsearch在没有找到匹配时返回None,找到时返回match object。

match object的方法

Method/Attribute Purpose
group() Return the string matched by the RE
start() Return the starting position of the match
end() Return the ending position of the match
span() Return a tuple containing the (start, end) positions of the match

match还是search?还是find*?

match只检查字符串从0位置开始是否符合,而search则会搜索整个字符串。
search只搜索自一次匹配,而findall则会搜索完整个字符串提供所有匹配。

贪婪和非贪婪方式

*,+,?等都是贪婪方式。但是后面加个?号改为匹配尽可能少的字符,即*?,+?,??,{m,n}?

标识

Flag Meaning
DOTALL, S Make . match any character, including newlines
IGNORECASE, I Do case-insensitive matches
LOCALE, L Do a locale-aware match
MULTILINE, M Multi-line matching, affecting ^ and $
VERBOSE, X Enable verbose REs, which can be organized more cleanly and understandably.
UNICODE, U Makes several escapes like \w, \b, \s and \d dependent on the Unicode character database.

一些定位元字符

Metacharacter Meaning
| or
^ 行首
$ 行位
\A 字符串首
\Z 字符串尾
\b 单词边界
\B 非单词边界

group分组

group()group(0)是匹配串,group(n)[n>0]是第n个子分组, group(L,m,n)可以接受多个index返回元祖,groups()返回所有匹配子组。

非捕获组(?:…)和命名组(?P…)

非捕获组不能后向引用了,比如只需要单词或的匹配但是又不想捕获它时。
(...)\1使用序号后向引用,(?P<name>...)(?P=name)后向引用命名组。

Lookahead Assertions

(?=...)确定性断言,(?!...)否定性断言。

简单分支判断

(?(id/name)yes-pattern|no-pattern)提供一个简单的分支判断,如果id/name组存在匹配,就检索匹配yes-pattern,否则检索匹配no-pattern,否定项可选可省略。

手动通知caffe快照操作等小技巧

caffe支持接受SIGHUP信号进行快照操作,所以命令就是:

# PID是caffe的进程号
kill -SIGHUP PID

# 查看PID的命令
ps -ef | grep caffe

# 或者使用pidof命令,这次一步完成
kill -SIGHUP $(pidof caffe)

使用caffe的solverstate继续训练的命令格式

./build/tools/caffe train --solver=solver.prototxt --snapshot=caffenet_train_iter_10000.solverstate

最简单caffe模型测试命令

import caffe
import numpy as np
import cv2
 
# 把图读进来解码
im = cv2.imread('000001.jpg',cv2.IMREAD_COLOR)
# 把图resize了 并转成网络input的shape大小
imblob=np.transpose(cv2.resize(im,(224,224)).reshape((1,224,224,3)),(0,3,1,2))
 
n = caffe.Net('deploy.prototxt','vgg16_iter_20000.caffemodel',caffe.TEST)
n.forward(data=imblob.astype(np.float32))

# 在直接取出输出层的结果即可,如
print n['cls_prob']

加密、解密、签名和验证签名

先来看看来源于Implementation of the Licensing System for a Software Product的一张图,很好地诠释了签名和验证签名的过程。

python使用Crypto库完成签名、验证签名、加密和解密的示例:signfile.py

shell中直接使用gpgopenssl等工具完成签名、验证签名、加密和解密。

注意:无论如何,记住这一点,私钥是不应该透露给别人的。

apache 使用 CGI 方式调用 python

设置方法:在xampp\apache\conf\httpd.conf中找到这行AddHandler cgi-script .cgi .pl .asp,添加.py成为AddHandler cgi-script .cgi .pl .asp .py,然后重启apache。

py脚本第一行写清楚python解释器就可以了,如我直接使用的是 Visual Studio 中的python,整个示例:

#!"C:/Program Files (x86)/Microsoft Visual Studio/Shared/Python36_64/python.exe"

# cgi sample

print("Content-type: text/html\n\n")
print("<html><head><title>Hello World from Python</title></head><body>Hello World from a Python CGI Script</body></html>")

放在xampp\htdocs中就可以了。

WAMP安装wsgi

配置

  1. https://www.lfd.uci.edu/~gohlke/pythonlibs/#mod_wsgi 上下来合适版本的二进制文件下载。
  2. 安装此wheel文件
    pip install mod_wsgi-4.5.24+ap24vc14-cp36-cp36m-win_amd64.whl

    ,注意管理员权限。

  3. 安装完成后再python的Scripts目录下会有mod_wsgi-express.exe文件,运行./mod_wsgi-express.exe module-config, 会给出需要写到httpd.conf中的配置内容
    LoadFile "c:/program files (x86)/microsoft visual studio/shared/python36_64/python36.dll"
    LoadModule wsgi_module "c:/program files (x86)/microsoft visual studio/shared/python36_64/lib/site-packages/mod_wsgi/server/mod_wsgi.cp36-win_amd64.pyd"
    WSGIPythonHome "c:/program files (x86)/microsoft visual studio/shared/python36_64"
    
  4. 将上面输出的配置项添加到httpd.conf的。取代别的配置指导说的
    LoadModule wsgi_module modules/mod_wsgi.so

    。然后在加上wsgialias即:

    LoadFile "c:/program files (x86)/microsoft visual studio/shared/python36_64/python36.dll"
    LoadModule wsgi_module "c:/program files (x86)/microsoft visual studio/shared/python36_64/lib/site-packages/mod_wsgi/server/mod_wsgi.cp36-win_amd64.pyd"
    WSGIPythonHome "c:/program files (x86)/microsoft visual studio/shared/python36_64"
    
    <IfModule wsgi_module>
    WSGIScriptAlias /hellowsgi C:/wamp64/www/hellowsgi.wsgi
    AddType text/html .py
    </IfModule>
    

然后就可以开始我们的helloworld了。 继续阅读WAMP安装wsgi