改善python程序-库

#库

掌握字符串的基本用法

性质判定

isalnum()、isalpha()、isdigit()、islower()、isupper()、isspace()、istitle()、 startswith(prefix[,start[, end]])、endswith(suffix[,start[, end]]),前面几个is*()形式的函数很简单,顾名思义无非是判定是否数字、字母、大小写、空白符之类的,istitle()作为东方人用得 少些,它是判定字符串是否每个单词都有且只有第一个字母是大写的。

査找与替换

count(sub[,start[,end]])、find(sub[,start[,end]])、index(sub[,start[,end]])、rfind(sub[,start[,end]])、rindex(sub[,start[,end]])这些方法都接受start、end参数.其中count()能够査找子串sub在字符串中出现的次数.此外,需要注意find()和index()方法的不同:find()函数族找不到时返回-1,index()函数族则抛出ValueError异常。
replace(old,new[,count])用以替换字符串的某些子串,如果指定count参数的话,就最多 替换count次,如果不指定,就全部替换.

字符串的分切与连接

partition(sep)、rpartition(sep)、splitlines([keepends])、split([sep[,maxsplit]])、rsplit([sep[,maxsplit]]), *partition()函数族是接受一个字符串参数,并返回一个3个元素的元组对象.如果sep没 出现在母串中,返回值是(sep,”,”);否则,返回值的第一个元素是sep左端的部分,第二个元素是sep自身,第三个元素是sep右端的部分.而spHt()的参数maxsplit是分切的次数,即最大的分切次数,所以返回值最多有maxsplit+1个元素.

变形

lower()、upper()、capitalize()、swapcase()、title(),titile()的功能是将每一个单词的首字母大写,并将单词中的非首字母转换为小写

删减与填充

删减是strip([chars])、lstrip([chars])、rstrip([chars])中的chars参数没有指定,就是删除空白符,空白符由string.whitespace常量定义.


按需选择sort()或者sorted()

1
2
>>> sorted(iterable[, cmp[, key[, reverse]]]}
>>> s.sort([cmp(key[, reverse]]]}
  • cmp为用户定义的任何比较函数,函数的参数为两个可比较的元素,函数根据第一个参数与第二个参数的关系依次返回-1、0或者+1(第一个参数小于第二个参数则返回负数)。
  • key是带一个参数的函数,用来为每个元素提取比较值
  • reverse表示排序结果是否反转
    sorted()函数会返回一个排序后的列表,原有列表保持不变;而Sort()函数会直接修改原有列表
    1
    2
    3
    4
    5
    6
    7
    8
    >>> a=[ '1', 'a', 3, 7, 'n']
    >>> sorted (a)
    [1, 3, 7, '1', 'a', 'n']
    >>> a
    [ '1', 'a', 3, 7, 'n']
    >>> print a.sort()
    >>> a
    [1, 3, 7, '1', 'a', 'n']
对字典进行排序
1
2
3
4
5
>>> phonebook = { ' Linda' : '7750 ', 'Bob' : ' 9345', 'Carol' : ' 5834 ' }
>>> from operator import itemgetter
>>> sorted_pb = sorted (phonebook.iteriterns (), key=itemgetter (1))
>>> print sorted_pb
[('Carol', '5834'), ('Linda', '7750'), ('Bob1,'9345')]
多维list排序
1
2
3
4
5
6
7
8
#分别表示学生的姓名,成绩,等级
>>> from operator import itemgetter
>>> gameresult = [['Bob', 95.00,'A'],['Alan',86.0, 'B'], ['Mandy',82.5,'A'], ['Rob',
86, 'E']]
#当第二个字段成绩相同的时候按照等级从低到高排序
>>> sorted (gameresult,key=operator.itemgetter(2, 1))
[['Mandy', 82.5,'A'], ['Bob', 95.0,'A'], ['Alan', 86.0,'C'],['Rob',86,,'E']]
字典中混合list排序
1
2
3
4
5
6
7
8
9
>>> mydict = {
... 'Li': ['M', 7],
... Zhang,:['E', 2],
... 'Wang': ['P',3],
... 'Du': ['C',2],
... 'Zhe': ['H',7]}
>>> from operator import itemgetter
>>> sorted(mydict.iteritems(), key»lambda (k,v): operator.itemgetter(1)(v))
List中混合宇典排序
1
2
3
4
>>> gameresult = [{ "name":"Bob", "wins":10, "losses":3, "rating":75.00 },{ "name":"David", "wins":3, "losses":5, "rating":57.00 }]
>>> from operator import itemgetter
>>> sorted(gameresult , key=operator.itemgetter("rating","name"))

使用copy模块深拷贝对象

(1)浅拷贝:构造一个新的复合对象并将从原对象中发现的引用插人该对象中。浅拷贝的实现方式有多种,如工厂函数、切片操作、copy模块中的copy操作等,如“copy.copy(customerl)”
(2)深拷贝:也构造一个新的复合对象,但是遇到引用会继续递归拷贝其所指向的具体内容,也就是说它会针对引用所指向的对象继续执行拷贝,因此产生的对象不受其他引用对象操作的影响。深拷贝的实现需要依赖copy模块的deepcopy()操作,如“copy.deepcopy(customerl)”

使用Counter进行计数统计

1
2
3
4
>>> from collections import Counter
>>> some_data = ['a','2',2,4,5,'2','b',4,7,'a',5,'d','a','z']
>>> print Counter(some_data)
Counter({'a': 3, 4: 2, 5: 2, '2': 2, 2: 1, 'b': 1, 7: 1, 'z': 1, 'd': 1})

使用elements()方法来获取Counter中的key值

1
2
>>> list (Counter(some_data).elements())
['a', 'a', 'a', 2, 'b', 4, 4, 5, 5, 7, '2', '2', 'z' 'd']

利用most_common()方法可以找出前N个出现频串最高的元累以及它们对应的次数

1
2
>>> Counter (some_data) .most_common (2)
[('a', 3), (4:2)]

update()方法用于被统计对象元素的更新,原有count()计数的对象与新增元素的统计计数值相加而不是直接替换它们.
subtmct()方法用于实现计数器对象中元素统计值相减,输人和输出的统计值允许为0或者负数。

1
2
3
4
5
6
7
8
>>> c = Counter ("success")
>>> c.update("successfully")
>>> c
Counter({'s': 6,'c': 4, 'u':3,'e':2,'f':1,'l':2,'y':1})
>>> c.subtract("successfully")
>>> c
Counter ({ 's':3, 'c':2, 'e':1, 'u': 1, 'f':0,...})


深入掌握ConfigParser

在ConfigParser支持的配置文件格式里,有一个[DEFAULT]节,当读取的配置项在不在指定的节里时, ConfigParser将会到[DEFAULT]节中査找.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 配罝文件:
$ cat example.conf
[DEFAULT]
in_default = 'an option value in default'
[section1]
$ cat readini.py
import ConfigParser
conf = ConfigParser.ConfigParser ()
conf.read('example.conf')
print conf.get('sectionl','in_default')
# 运行结果如下
$ python readini.py
'an option value in default'

配置项值的査找规则如下
  • 如果找不到节名,就拋出NoSectionError。
  • 如果给定的配置项出现在get()方法的vars参数中,则返回vars参数中的值。
  • 如果在指定的节中含有给定的配置项,则返回其值。
  • 如果在[DEFAULT]中有指定的配置项,则返回其值。
  • 如果在构造函数的defaults参数中有指定的配置项,则返回其值。
  • 拋出NoOptionError
ConfigParser支持类似Python中字符串格式化
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
$ cat format.conf
[DEFAULT]
conn_str = '%(dbn)s://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s'
dbn = mysql
user = root
host = localhost
port = 3306
[dbl]
user = aaa
pw=ppp
db = example
[db2]
host = 192.168.0.110
pw = www
db = example
# 通过不同的节名来获取格式化后的值时,根据不同配置,得到不同的值
$ cat readformatini.py
import ConfigParser
conf = ConfigParser.ConfigParser()
conf.read('format.conf')
print conf.get('dbl', 'conn_str')
print conf.get('db2', 'conn_str')
$ python readformatini.py
mysql ://aaa : ppp@localhost: 3306/example
mysql ://root: www@192.168.0.110: 3306/example
getboolean()根据一定的规则将配置项的值转换为布尔值

getboolean()的真值规则: no、false和off都会被转义为False,而对应的1、yes、true和on则都被转义为True,其他值都会导致抛出VahieError异常。


使用argparse处理命令行参数

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-s', action='store', dest='simple_value',
help='Store a simple value')
parser.add_argument('-c', action='store_const', dest='constant_value',
const='value-to-store',
help='Store a constant value')
parser.add_argument('-t', action='store_true', default=False,
dest='boolean_switch',
help='Set a switch to true')
parser.add_argument('-f', action='store_false', default=False,
dest='boolean_switch',
help='Set a switch to false')
parser.add_argument('-a', action='append', dest='collection',
default=[],
help='Add repeated values to a list')
parser.add_argument('-A', action='append_const', dest='const_collection',
const='value-1-to-append',
default=[],
help='Add different values to list')
parser.add_argument('-B', action='append_const', dest='const_collection',
const='value-2-to-append',
help='Add different values to list')
parser.add_argument('--version', action='version', version='%(prog)s 1.0')
results = parser.parse_args()
print 'simple_value =', results.simple_value
print 'constant_value =', results.constant_value
print 'boolean_switch =', results.boolean_switch
print 'collection =', results.collection
print 'const_collection =', results.const_collection
$ python argparse_action.py -h
usage: argparse_action.py [-h] [-s SIMPLE_VALUE] [-c] [-t] [-f]
[-a COLLECTION] [-A] [-B] [--version]
optional arguments:
-h, --help show this help message and exit
-s SIMPLE_VALUE Store a simple value
-c Store a constant value
-t Set a switch to true
-f Set a switch to false
-a COLLECTION Add repeated values to a list
-A Add different values to list
-B Add different values to list
--version show program's version number and exit
$ python argparse_action.py -s value
simple_value = value
constant_value = None
boolean_switch = False
collection = []
const_collection = []
支持类型增多

在type参数的值不再是一个字符串,而是一个可调用对象,比如在add_option()调用时是type=”int”,而在add_argument()调用时直接写type=im就可以了.argparse还支持文件类型.
扩展类型可调用任何对象,比如函数都可以作为type的实参.与type类似,choices参数也支持更多的类型.

1
parser.add_argument('door', type=int, choices=range(1, 4))

add_argument()提供了对必填参数的支持,只要把required参数设置为True传递进去,当缺失这一参数时,argparse就会自动退出程序,并提示用户。

支持参数分组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> parser = argparse.ArgumentParser(prog='PROG', add_help=False)
>>> group1 = parser.add_argument_group('group1', 'groupl description')
>>> group1.add_argument('foo', help = 'foo help')
>>> group2 = parser.add_argument_group('group2', 'group2 description')
>>> group2 .add_argument ('--bar', help='bar help')
>>> parser.print_help()
usage: PROG [--bar BAR] foo
group1:
group1 description
foo foo help
group2:
group2 description
--bar BAR bar help
支持子命令
1
2
3
4
5
6
7
>>> import argparse
>>> parser = argparse.ArgumentParser(prog=' PROG')
>>> subparsers = parser.add_subparsers(help='sub-command help')
>>> parser_a = subparsers.add_parser('a', help='a help')
>>> parser_a.add_argument('--bar', type=int, help='bar help')
>>> parser.parse_args(['a', '--bar', '1'])
Namespace(bar=l)

使用pandas处理大型CSV文件(一种逗号分隔型值的纯文本格式文件)

常见的API

1) reader(csvfile[,dialect=’excel’][,fmtparam])
参数csvfile需要是支持迭代(Iterator)的对象,通常对文件(file)对象或者列表(list)对象都是适用的,并且每次调用next()方法的返回值是字符串(string);参数dialect的默认值为excel,;fmtparam是一系列参数列表,主要用于需要覆盖默认的Dialect 设置的情形。
2) csv.writer(csvfile,dialect=’excer’,fmtparams),用于写入CSV 文件**

1
2
3
4
5
with open('data.csv','wb') as csvfile:
csvwriter=csv.writer(csvfile, dialect='excel',delimiter="|",quotechar='H', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow (["1/3/09 14:44","'Productl'","1200''","Visa","Gouya"])
#写入行输出形式为:
1/3/09 14:44 | 'Productl' |1200'' |Visa|Gouya

3)csv.DictReader(csvfile, fieldnames=None, restkey=None, restval=None, dialect-exceP, *args,kwds)
将读入的信息映射到一个字典中去,其中字典的key由fieldnames指定,该值省略的话将使用CSV文件第一行的数据作为key值.如果读入行的字段的个数大于filednames中指定的个数,多余的字段名将会存放在restkey中,而restval主要用于当读取行的域的个数小于fieldnames的时候,它的值将会被用作剩下的key对应的值.
4)csv.DietWriter(csvflle, fieldnames, restval=’’, extrasaction=’raise’, dialect=’excer’, args, *kwds>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import csv
with open ('test.csv', 'wb') as csv_file:
#设置列名称
FIELDS = ['Transaction__date', 'Product', 'Price', 'Payment__Type']
writer = csv. DictWriter(csv_file, fieldnames=FIELDS)
# 參写入列名称
writer.writerow(diet(zip(FIELDS, FIELDS)))
d = {'Transaction_date1':'1/2/09 6:17', 'Product':'Productl', 'Price': '1200','Payment_Type':'Mastercard'}
# 写入一行
Writer .writerow (d)
with open ('test.csv', 'rb') as csv_file:
for d in csv.DictReader(csv_file):
print d
#output d is:{'Product':'Productl','Transaction_date': '1/2/09 6:17','Price':'1200','Payment_Type': 'Mastercard'}

Pandas的使用

Pandas支持多种文件格式处理,包括CSV、HDF5、HTML等,其支持的两种数据结构——Series和DataFrame—是数据处理的基础。
(1)Series:它是一种类似数组的带索引的一维数据结构。如果不指定索引,默认为0到N-1。通过obj.valuesO和obj.indexO可以分别获取值和索引。当给Series传递一个字典的时候,Series的索引将根据字典中的键排序。如果传入字典的时候同时重新指定了index参数,当index与字典中的键不匹配的时候,会出现时数据丢失的情况,标记为NaN。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> objl = Series([l,'a',(1,2),3], index=['a', 'b', 'c','d'])
>>> objl
a 1
b a
c (1, 2)
d 3
dtype: object
>>> obj2=Series ({"Book":"Python", "Author":"Dan", "ISBN":"011334", "Price":25},index=['book','Author','ISBM','Price'])
>>> obj2 . isnull ()
book True #指定的index与字典的鍵不匹配,发生数据丟失
Author False
ISBM True #指定的index与字典的鍵不匹配,发生数据丟失
Price False
dtype: bool

(2)DataFrame:其数据为排好序的数据列的集合,每一列都可以是 不同的数据类型,索引会自动分配并且能根据指定的列进行排序。构建一个DataFrame最常用的方式是用一个相等长度列表的字典或NumPy数组。DataFrame也可以通过columns指定序列的顺序进行 排序。

1
2
3
4
5
6
7
8
>>> data = {'OrderDate': ['l-e-lO', '1-23-10', '2-9-10', '2-26-10', '13-15-10'], 'Region':['East', 'Central', 'Central', 'West', 'East'], 'Rep': ['Jones', 'Kivell', 'Jardine', 'Gill', 'Sorvino']}
>>> DataFrame(data, columns= ['OrderDate','Region', 'Rep']}
OrderDate Region Rep
0 1-6-10 East Jones
1 1-23-10 Central Kivell
2 2-9-10 Central Jardine
3 2-26-10 West Gill
4 3-15-10 East Sorvino

Pandas中处理CSV文件的函数

read_csv()和to_csv()这两个,其中read_csv()读取CSV文件的内容并返回DataFmme, to_csv()则是其逆过程

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# csv文件
# OrderDate,Region,Rep,Item,Units,Unit Cost,Total 1-6-10,Eastf Jones,Pencil,95, 1.99 , 189.05
# 1-23-10,Central,Binder,SO, 19.99 , 999.50
# 2-9-10,Central,Jardine,Pencil/ 36, 4.99 , 179.64
# 2-26-10,Central,Gill,Pen,27, 19.99 , 539.73
# 3-15-10,WestfPencil,56/ 2.99 , 167.44
# 4-1-10,East,Jones,Binder, 60, 4.99 , 299.40 4-18-10,Central,Andrews,Pencil, 75, 1.99 , 149.25
# 方法read_csv()的参数nrows指定读取文件的行数,usecols指定所要读取的列的列名
>>> df = pd.read_csv("SampleData.csv", nrows=5, usecols=['OrderDate', 'Item', 'Total'])
>>> df
OrderDate Item Total
0 1-6-10 Pencil 189.05
1 1-23-10 Binder 999.50
2 2-9-10 Pencil 179.64
3 2-26-10 Pen 539.73
4 3-15-10 Pencil 167.44
# 设置CSV文件与excel兼容。dialect参数可以是string也可以是csv.Dialect的实例
# 如果文件格式改为使用“丨”分隔符,则需要设置dialect相关的参数。
# error_ bad_lines设置为False,当记录不符合要求的时候,如记录所包含的列数与文件列设置不相 等时可以直接忽略这些列。
>>> dia = csv.excel ()
>>> dia.delimiter = "|" # 设置分隔符
>>> pd.read_csv("SD.csv")
OrderDateI Region I Rep I Item I Units I Unit Cost I Total
0 1-6-101 East I Jones I Pencil 19511.99 1189.05
1 1-23-10|Central|Kivell|Binder|50|19.99 1999.50...
>>> pd.read_csv("SD.csv",dialect =dia,error_bad_lines=False)
Skipping line 3: expected 7 fields, saw 10 #所有不符合格式要求的列将直接忽略
OrderDate Region Rep Item Units Unit Cost Total
0 1-6-10 East Jones Pencil 95 1.99 189.05
# 对文件进行分块处理并返回一个可迭代的对象
# 参数chunksize设置分块的文件行数
# 将参数iterator设置为True时,返回值为TextFileReader,它是一个可迭代对
>>> reader = pd.read_table("SampleData.csv", chunksize=10, iterator=True)
>>> reader
<pandas.io.parsers.TextFileReader object at 0x0314BE70>
>>> iter(reader).next() # 将 TextFileReader 转换为迭代器并调用 next 方法
OrderDate, Region, Rep, Item, Units, Unit Cost, Total # 毎次读入 10 行
0 1-6-10, East,Jones,Pencil,95, 1.99189.05
1 1-23-10,Central,Kiveil,Binder,50, 19.99 , 999.50
2 2-9-10,Central,Jardine,Pencil, 36, 4.99 , 179.64
...
# 支持多个文件合并处理
>>> filelst = os.listdir("test")
>>> print filelst #同时存在3个格式相同的文件
('si.csv', 's2.csv', 's3.csv')
>>> os.chdir("test")
>>> dfs = [pd.read_csv(f) for f in filelst]
>>> total_df = pd.concat(dfs) # 将文件合并
>>> total_df
OrderDate Region Rep Item Units Unit Cost Total
0 1-6-10 East Jones Pencil 95 1.99 189.05
1 1-23-10 Central Kivell Binder 50 19.99 999.5


使用ElementTree解析XML

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
28
29
30
31
32
33
34
<systems>
<system platform="linuxM name="linuxtest">
<purpose>automation test</purpose>
<system_type>virtual</system_type>
<ip_address/>
<commands_on_boot>
<command_details>
<!-- Set root password.-->
<command>echo rootrmytestpwd I sudo /usr/ sbin/chpasswd</command>
<userid>root2</userid>
<password>PasswOrd</password>
</command_details>
<command_detai1s >
<c<MTfnand>mkdir /TEST; chmod 111 /TEST</command>
</command_details>
</commands_on_boot>
</system>
<system platform="aix" name=MaixtestM>
<purpose>manual test</purpose>
<system_type>virtual</system_type>
<ip_address/>
<commands_on_boot>
<command details〉
<!-- Set root password.-->
<command>echo root:mytestpwd | sb in/chpasswd</command>
<userid>root2</userid>
<password>PasswOrd</password>
</command details>
<command_details>
<command>mkdir /TEST; chmod 777 /TEST</cornmand>
</command_details>
</commands on boot>
</system>
</systems>

模块ElementTree主要存在两种类型ElementTree和Element

ElementTree主要的方法和使用示例
主要的方法、属性方法说明以及示例
getroot()返回xml文档的根节点 >>> import xml.etrce.ElementTree as ET >>> tree = ET.ElementTrce(file =”test.xral”) >>> root = tree.getroot() >>> print root
find(match) findall(match) findtext(match, dcfault=None)同Element相关的方法类似,只是从跟节点开始搜索(见表冬2) >>> for i in,root.findall(“system/purpose”): … print i.text automation test manual test >>> print root.findtext(wsystem/purpose”) automation test >>> print root.find(“system/purpose”) 〈Element purpose at 0x26d2170>
iter(tag=None)从xm丨根结点开始,根据传人的元素的tag返回所有的元索集合的迭代器 >>> for i in tree.iter(tag=”command”): … print i.tcxt echo root:mytestpwdsudo /usr/sbin/chpasswd mkdir /TEST; chmod 777 /TEST echo root:mytestpwdsudo /usr/sbin/chpasswd mkdir /TEST; chmod 777 /TEST
iterfind(match)根据传人的lag名称或者path以迭代器的形式返回所有的子元素 >>> for i in,tree-iterfindCsystem/purpose”): … print i.text automation test manual test
Element主要的方法和使用示例
主要的方法、属性方法说明以及示例
tag字符串.用来表示元素所代表的名称>>> print root[l].tag # 输出 system
text表示元索所对应的具体值>>> print root丨l].text # 输出空串
attrib用字典表示的元素的属性>>> print root[l].attrib # 输出{•platform: ’aix’, ‘name: ’sixtest’}
gct(kcy, default=Nonc)根据元素属性字典的key值获取对应的值,如果找不到对应的厲性,则返回,default >>> print root[l].attrib.get(“platform”)# 输出 aix
itcms()将元素届性以(名称,值)的形式返冋>>> print root[l].items() ^[(‘platform’, ‘aix’),(‘name’, ‘aixtest’)]
keys()返回元素属性的key值集合>>> print root[l].keys() # 输出[’platform’,•name’]
find(match)根据传入的tag名称或者path返回第一个对应的element对象,或者返回 None
findall(match)根据传入的tag名称或者path以列表的形式返回所有符合条件的元索
findtext(match, default=None)根据传人的tag名称或者path返回第一个对应的element对象对应的值,即 text属性,如果找不到则返回default的设置
list(elem)根据传入的元素的名称返冋其所有的子节点>>> for i in list(root.findall(“system/system_typeM)):… print i.text
iteiparse的使用示例:统计userid在整个XML出现的次数
1
2
3
4
5
6
7
8
>>> count = 0
>>> for event, elein in ET.iterparse("test. xml"): # 对 iterparse 的返回值进行迭代
... if event =='end':
... if elem.tag ==,userid':
... count+=l
... elem.clear()
>>> print count 2
>>>

理解模块pickle优劣

pickle中最主要的两个函数对为dumpO和load()

  • pickle.dump(obj, file[, protocol]):序列化数据到一个文件描述符(一个打开的文件、
    套接字等)。参数obj表示需要序列化的对象,包括布尔、数字、字符串、字节数组、 None、列表、元组、字典和集合等基本数据类型,此外pidke还能够处理循环,递归引用对象、类、函数以及类的实例等。参数file支持write()方法的文件句柄,可以为真实的文件,也可以是Stringl()对象等。protocol为序列化使用的协议版本,0表示 ASCII协议,所序列化的对象使用可打印的ASCII码表示;1表示老式的二进制协议;2表示2.3版本引人的新二进制协议
  • load(file):表示把文件中的对象恢复为原来的对象,这个过程也被称为反序列化。
1
2
3
4
5
6
7
8
9
10
11
>>> import cPickle as pickle
>>> my_data = {"name" : "Python", "type" : "Language", "version" : "2-7.5"}
>>> fp = open("picklefile.dat", "wb")
>>> pickle.dump(my_data, fp) #使用 dump 进行序列化
>>> fp.close()
>>> fp = open("picJclefile.dat", "rb")
>>> out = pickle.load(fp)
>>> print(out)
{"name" : "Python", "type" : "Language", "version" : "2-7.5"}
>>> fp.close ()

(1)支持的数据类型广泛:如数字、布尔值、宇符串,只包含可序列化对象的元组、字 典、列表等,非嵌套的函数、类以及通过类的dict或者getstate()可以返回序列化对象的实例等。
(2)pickle模块是可以扩展的:对于实例对象,pickle在还原对象的时候一般是不调
函数的,如果要调用init()进行初始化,对于古典类可以在类定义中提供getinitargs()函数,并返回一个元组,当进行unpickle的时候,Python就会自动调用 init_(),并把getinitargs()中返回的元组作为参数传递给init(),而对于新式类,可以提供getnewargs()来提供对象生成时候的参数,在unpickle的时候以Class.new (Class, *arg)的方式创建对象。对于不可序列化的对象,如sockets、文件句柄、数据库连 接等,也可以通过实现pickle协议来解决这些局限,主要是通过特殊方法getstate()和setstate__()来返回实例在被pickle时的状态。

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
28
29
30
import cPickle as pickle
class TextReader:
def __init__(self,filename):
self.filename = filename
self.file = open(filename)
self.postion = self.file.tell () # 文件的位置
def readline(self):
line = self.file.readline()
self.postion = self.file.tell()
if not line:
return None
if line.endswith('\n'):
line = line[:-l]
return "%i: %s" %(self.postion, line)
def _getstate_(self) : # 记录文件被pickle时候的状态
state = self.__diet__.copy () # 获取被 pickle 时的字典信息
del state['file']
return state
def _setstate (self, state) : # 设置反序列化后的状态
self.__diet__.update(state)
file = open(self.filename)
self.file = file 
reader = TextReader("zen.txt")
print(reader.readline ())
print(reader.readline())
s = pickle.dumps(reader) # 在 dumps 的时候会默认调用 _getstate_
news_reader = pickle.loads(s) # 在 loads 的时候会默认调用 setstate_
print(new_reader.readline())

(3)维护对象间的引用,如果一个对象上存在多个引用,pickle后不会改变对象间的引用,并且能够自动处理循环和递归引用。

1
2
3
4
5
6
7
8
9
10
11
12
>>> a = ['a', 'b']
>>> b = a
>>> b.append('c')
>>> p = pickle.dumps((a,b))
>>> al,bl = pickle.loads(p)
>>> al
['a','b','c']
>>> bl
['a','b','c']
>>> a.append('d')
>>> bl
['a','b','c','d']


序列化的另一个不错的选择——JSON

Python的标准库JSON提供的最常用的方法是dump/dumps用来序列化,load/loads用来反序列化。需要注意的json默认不支持非ASCII-based的编码,如load方法可能在处理中文字符时不能正常显示,则需要通过 encoding参数指定对应的宇符编码

JSON文档的构成非常简单,仅存在以下两大数据结构
  • 称/值对的集合。在各种语言中,它被实现为一个对象、记录、结构、字典、散列
    表、键列表或关联数组
  • 值的有序列表
    json模块利用了编码(JSONEncoder)和解码类(JSONDecoder)拓展其他类型
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import datetime
    from time import mktime
    try:
    import simplejson as json
    except ImportError: import json
    class DateTimeEncoder (json. JSONEncoder):
    def default(self, obj):
    if isinstance(obj, datetime.datetime):
    return obj.strftime("%Y-%m-%d %H:%M:%S")
    elif isinstance(obj, date):
    return obj.strftime("%Y-%m-%d")
    return json.JSONEncoder.default(self, obj)
    d=datetime.datetime.now()
    print json.dumps(d, cls=DateTimeEncoder)

使用traceback获取栈信息

程序运行会输出异常发生时候完整的栈信息,包括调用顺序、异常发生的语句、错误类型等.traceback.print_exc()方法打印出的信息包括3部分:错误类型、错误对应的值以及具体的trace信息,包括文件名、具体的行号、函数名以及对应的源代码。

1
2
3
4
5
6
7
8
9
10
11
12
Traceback (most recent call last):
File "trace.py", line 20, in <module>
f ()
File "trace.py", line 5, in f
return g ()
File ''trace.py", line 8, in g
return h()
File "trace.py", line 12, in h
return i ()
File "trace.py", line 16, in i
print gList [7]
IndexError: list index out of range

常用的方法

(1)traceback.print_exception(type, value, traceback[,file]]),根据limit的设置打印栈信息,file为None的情况下定位到sys.stderr,否则写入文件;其中type、value、 traceback这3个参数对应的值可以从sys.exc_info()中获取。
(2)raceback.print_exc([limit[,file]]),为 print_exception()函数的缩写,不需要传入 type、 value、traceback 这3个参数。
(3)traceback.format_exc([limit]),与print_exc()类似,区别在于返回形式为字符串。
(4)traceback.extract_stack([file,[, limit]]),从当前帧中提取 trace信息。
(5)本质上模块trackback获取异常相关的数据都是通过syS.exc_info()函数得到的.当有异常发生的时候,该函数以元组的形式返回(type, value,traceback), 其中type为异常的类型,value为异常本身,traceback为异常发生时候的调用和堆栈信息,它是一个traceback对象,对象中包含出错的行数、位置等数据。
(6)inspect模块也提供了获取traceback对象的接口inspect.trace([conext]),可以返回当前帧对象以及异常发生时进行捕获的帧对象之间的所有栈帧记录列表,因此第一个记录代表当前调用对象,最后一个代表异常发生时候的对象。其中每一个列表元素都是一个由6个元素组成的元组:(frame对象,文件名,当前行号,函数名,源代码列表,当前行在源代码列表中的位置)


使用logging记录日志信息

logger的level分为5个级别, 可以通过Logger.setLevel(lvl)来设置,其中DEBUG为最低级别,CRITICAL为最高级别,默认的级别为WARNING。
| Level | 使用情形 |
|———-|————————————————————————-|
| DEBUG | 详细的信息,在追踪问题的时候使用 |
| INFO | 正常的信息 |
| WARNING | 一些不可预见的问题发生,或者将要发生.如磁盘空间低等,但不影响程序的运行 |
| ERROR | 由于某些严重的问题,程序中的一些功能受到影响 |
| CRITICAL | 严重的错误,或者程序本身不能够继续运行 |

logging lib包含以下4个主要对象

(1)logger是程序信息输出的接口,并根据设置的日志级别或filter来决定哪些信息需要输出,并 将这些信息分发到其关联的handler。常用的方法有Logger.setLevel()、Logger.addHandler()、Logger.removeHandler()、Logger.addFilter()、Logger.debug()、Logger.info()、Logger. waming()、Logger.error()、etLogger()
(2)Handler用来处理信息的输出,可以将信息输出到控制台、文件或者网络。可以通过 Logger.addHandler()来给 logger 对象添加 handler,常用的 handler 有 StreamHandler 和FileHandler类。StreamHandler发送错误信息到流,而FileHandler类用于向文件输出日志信息,这两个handler定义在logging的核心模块中。其他的handler定义在logging.handles 模块中,如 HTTPHandler、SocketHandler。
(3)Formatter决定log信息的格式,格式使用类似于%(< dictionary key >)s的形式来定义,如’%(asctime)s-%(levelname)s - %(message)s’。
(4)Filter用来决定哪些信息需要输出。可以被handler和logger使用,支持层次关系,比如,如果设罝了filter名称为A.B的logger,则该logger和其子logger的信息会被输出,如 A.B、A.B.C.
(5)logging.basicConfig([kwargs])提供对日志系统的基本配置**,默认使用StreamHandler和 Formatter并添加到root logger
| 格 式 | 描 述 |
|———-|———————————————————|
| filename | 指定FileHandler的文件名,而不是默认的StreamHandler |
| filcmodc | 打幵文件的模式,同open函数中的同名参数,默认为’a’ |
| format | 输出格式字符串 |
| datefmt | 日期格式 |
| level | 设置根logger的日志级别 |
| stream | 指定StrcamHandler。这个参数若与filename冲突,忽略stream |

范例
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import traceback
import sys
import logging
gList = ['a','b','c','d','e','f'g']
logging.basicConfig( # K置日志的输出方式及格式
level=logging.DEBUG,
filename= 'log. txt',
filemode='w',
format=' % (asctime) s % (filename) s [line: % (lineno) d) % (Xevelname) s % (message) s ',)
def f ():
gList[5]
logging.info('[INFO]:calling method g() in f()') # 记录正常的信患 return g()
def g():
logging.info('[INFOJ:calling method h() in g()') return h() def h ():
logging.info('[INFO]:Delete element in gList in h()')
del gList[2]
logging.info('[INFO]:calling method i() in h()')
return i()
def i ():
logging.info('[INFO]:Append element i to gList in i()')
gList.append('i')
print gList[7]
if __name__ == '__main__':
logging.debug('Information during calling f():')
try:
f()
except IndexError as ex:
print "Sorry, Exception occured, you accessed an element out of range"
ty,tv,tb = sys.exc_info()
logging.error("[ERROR]:Sorry,Exception occured,you accessed an element out of range")
logging.critical('object info:%s' %ex)
logging.critical ('Error Type:{0} Error Inforrration: {1}'.forrrat (ty, tv))
logging.critical (''.join (trackback.formt_tb(tb)))
2013-06-26 12:05:18,923 traceexample.py[line:41] CRITICAL object info:list index out of range
2013-06-26 12:05:18,923 traceexample.py[line:42] CRITICAL Error Type: <type 'exceptions.IndexError'>,Error Information:list index out of range
2013-06-26 12:05:18,924 traceexaraple.py[line:43] CRITICAL File "traceexample.py", line 35, in <module>
f ()
File "traceexample.py" line 15, in f
return g()
File "traceexample.py" line 19, in g
return h()
File "traceexample.py" line 25, in h
return i()
File wtraceexample.py" line 30, in i
print gList[7]
控制运行输出到console
1
2
3
4
5
console = logging.StreamHandler()
console.setLevel(logging.ERROR)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)

使用threading模块编写多线程程序(thread和 threading)

Python多线程支持用两种方式来创建线程:一种是通过继承Thread类,重写它的run()方法(不是start()方法);另一种是创建一个threading.Thread对象,在它的初始化函数(init())中将可调用对象作为参数传入
(1)thread模块只提供了一种锁类型thread_LockType,而threading模块中不仅有Lock指令锁、RLock可重入指令锁,支持条件变量Condition,信号量Semaphore,BoundedSemaphore以及Event事件等
(2)threading中的join()方法能够阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import threading, time,sys
class test(threading.Thread):
def __init__(self,name,delay):
threading.Thread.__init__(self)
self.name = name
self.delay = delay
def run(self):
print "%s delay for %s" %(self.name,self.delay)
time.sleep(self.delay)
c = 0
while True:
print "This is thread %s on line %s" %(self.namer c)
c = c + 1
if c == 3:
print "End of thread %s" %self.name
break
tl = test('Thread 1', 2)
t2 = test('Thread 2', 2)
tl.start()
print "Wait tl to end"
tl.join()
t2.start()
print "End of main"

主线程main在tl上使用join()的方法,主线程会等待tl结束后才继续运行后面的语句,由于线程t2的启动在join语句之后,t2一直等到tl退出后才会幵始运行。
(3)thread模块不支持守护线程,threading模块支持守护线程,可以通过setDaemon()函数来设定线程的daemon属性。当daemon属性设置为True的时候表明主线程的退出可以不用等待子线程完成。默认情况下,daemon标志为False,所有的非守护线程结束后主线程才会结束。

使用Queue使多线程编程更安全

Queue模块提供了 3种队列
  • Queue.Queue(maxsize):先进先出,maxsize为队列大小,其值为非正数的时候为无限循环队列。
  • Queue.LifoQueue(maxsize):后进先出,相当于栈。
  • Queue.PriorityQueue(maxsize):优先级队列。
队列支持以下方法
  • Queue.qsize():返回近似的队列大小
  • Queue.empty():列队为空的时候返回True,否则返回False。
  • Queue.full():当设定了队列大小的情况下,如果队列满则返回True,否则返回False。
  • Queue.put(item [,block[,timeout]]):往队列中添加元素item, block设置为False的时候,如果队列满则抛出Full异常.如果block设置为True,timeout为None的时候则会一直等待直到有空位置,否则会根据timeout的设定超时后拋出Full异常。
  • Queue.put_nowait(item):等价于put(item,False)
  • Queue.get([block[, timeout]]):从队列中删除元索并返回该元素的值。
  • Queue.get_nowait():等价于get(False)。
  • Queue.task_done():发送信号表明人列任务已经完成,经常在消费者线程中用到。
  • Queue.join():阻塞直至队列中所有的元素处理完毕。
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
28
29
30
31
32
33
34
35
36
37
38
import os
import Queue
import threading
import urllib2
class DownloadThread(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
while True:
url = self.queue.get()
print self.name + "begin download"+url+"..."
self.download_file(url)
self.queue.task_done()
print self.name + "end download"+url+"..."
def download_file(self,url):
urlhandler = urllib2.urlopen(url)
fname = os.path.basename(url) + ".html"
with open (fname, "wb") as f:
while True:
chunk = urlhandler.read(1024)
if not chunk: break
f.write(chunk)
if __name__ == "__main__":
urls = ["http://wiki.python.org/moin/WebPrograrnming",
"https://www.createspace.com/3611970",
"http ://wiki .python.org/moin/Documentation"]
queue = Queue.Queue()
for i in range (5):
t = DownloadThread(queue)
t.setDaemon(True)
t.start ()
for url in urls:
queue.put(url)
queue.join()