Python Cookbook 2——Python技巧

对象拷贝

  • new_list = copy.copy(existing_list)浅拷贝,虽然生成一个新对象,但是对象内部的属性和内容仍然引用原对象,一旦修改一个,两个均被改变。
  • new_list = copy.deepcopy(existing_list) 深拷贝,修改new_list同时不改变existing_list。这种拷贝会消耗相当的时间和内存。

若列表中某元素存在则返回之

def list_get(L,i,v=None):
    if -len(L)return L[i]
    else: 
        return v

def list_get(L,i,v=None):
    try:
        return L[i]
    except IndexError:
        return v

#'获得原谅总是比获得许可容易(easier to get forgiveness than permission,EGFP)'

循环访问序列中的元素和索引

  • for i,j in enumerate(list)
  • d = dict(enumerate(L))利用enumerate将列表生成字典

展开一个嵌套的序列

def list_or_tuple(x):   
    return isinstance(x,(list,tuple))

def flatten(sequence,to_expand=list_or_tuple):
    for item in sequence:
        if to_expand(item):
            for subitem in flatten(item,to_expand):
                yield subitem
        else:
            yield item

l = [1,2,[3,4],5,[6]]
for i in flatten(l):
    print i,


out:
1 2 3 4 5 6

二维矩阵行列变换

1方案:
a = [[1,2,3],[4,5,6],[7,8,9],[10,11,12]]
print [[i[j] for i in a]for j in xrange(len(a[0]))]
out:
[[1,4,7,10],[2,5,8,11],[3,6,9,12]]

2方案:
print map(list,zip(*a))#达到目的,但晦涩难懂

在无需过多援引的情况下创建字典

  • d=dict(zip(the_keys,the_values))the_keys是键的序列,the_values是键对应的值的序列,内建的zip函数创建并返回一个数对(key,value)构成的列表,内建的dict接受这个列表作为参数并创建相应的字典。适合短序列
  • 对于长序列,可使用python标准库中的itertools模块提升速度。二者区别:zip会在内存中创建出包含所有数对的列表,而itertools.izip一次只生成一对数据。
import itertools
d = dict(itertools.izip(the_keys,the_values))

将列表元素交替地作为键和值来创建字典

  • 对扩展的列表切片调用内建函数zip:
def dictFromList(d):
    return dict(zip(d[::2],d[1::2]))
  • 通用的适合任何序列或者可迭代参数的方式是:
def pairwise(iterable):
    itnext = iter(iterable).next
    while True:
        yield itnext(),itnext()

def dictFromSequence(seq):
    return dict(pairwise(seq))
  • 两种方法实质上是用同样的方法创建字典:都生成一个(key,value)序列,并将其作为参数传递给dict。区别:
    • 前者:使用切片操作,两个切片分别根据奇偶索引搜索元素。局限是:只支持扩展切片的类型或者类的实例,如list、tuple和str;且会在内存中创建临时列表,耗内存;
    • 后者:使用生成器创建(key,value)序列。适合任何可迭代对象list、tuple、str,还包括其他生成器的结果、文件、字典等。且一次只生成一对(key,value),没有在内存中创建表,性能高。pairwise函数的实现:将内建函数iter应用于传入的iterable参数,获得一个迭代器,然后再将一个本地变量itnext绑定到这个迭代器的next方法。看上去有点奇怪,但这是python中一个很好的通用技巧:如果你有一个对象,你想对这个对象所做的事是在循环中不断调用它的一个方法,可以给它的这个被绑定的方法赋予一个本地的名字,然后就可以直接直接调用这个本地名字了,就像调用一个函数一样。

获取字典的一个子集

  • 若不想改动原字典:
def sub_dict(the_dict,somekeys,default=None):
    return dict((k,the_dict.get(k,default)) for k in somekeys)

d = {'a': 1, 'c': 3, 'b': 2}
sub_dict(d,'ab'),d
out:
{'a': 1, 'b': 2}, {'a': 1, 'c': 3, 'b': 2}
  • 若想从原字典中删除那些符合条件的条目:
def sub_dict_remove(the_dict,somekeys,default=None):
    return dict((k,the_dict.pop(k,default)) for k in somekeys)

d = {'a': 1, 'c': 3, 'b': 2}
sub_dict_remove(d,'ab'),d
out:
{'a': 1, 'b': 2}, {'c': 3}
  • 若键不匹配,抛出错误:
def sub_dict(the_dict,somekeys):
    return dict((k,the_dict[k]) for k in somekeys)

def sub_dict_remove(the_dict,somekeys):
    return dict((k,the_dict.pop(k) for k in somekeys)
  • 键不匹配时将其忽略:
def sub_dict(the_dict,somekeys):
    return dict((k,the_dict[k]) for k in somekeys if k in the_dict)

def sub_dict_remove(the_dict,somekeys):
    return dict((k,the_dict.pop(k) for k in somekeys if k in the_dict)

字典的一键多值

  • 允许键所对应的值重复
d1 = {}
d1.setdefault(key,[]).append(value)#list作为字典的值
d1[key].remove(value)#删除键对应的值

d2 = {}
d2.setdefault(key,{})[value1]=value2#子字典作为字典的值
del d2[key][value]
  • 键所对应的值不可重复
d3 = {}
d3.setdefault(key,set()).add(value)
d3[key]remove(value)

用字典分配方法和函数

在解决多分支语句时,常使用的方法是多个case或者if和else或者if和else if。但这种方法效率比较低,可读性不高。在python中,字典可使得多分支语句更容易被解决。具体的作法就是把在某个条件下要执行的过程写成一个函数,然后把该条件本身和对应的函数作为一对Key-Value放入一个字典中,该字典相当于一个Map。在别的语言中,可能需要使用case、switch、或者if else语句,但在python中,都可以使用字典的这个功能来解决。
如:求一个数除以10的余数,并打印出来,可以这样写:

while True:
    n = raw_input()
    i = int(n) % 10
    if i == 0:
        print 0
    elif i == 1:
        print 1
    elif i == 2:
        print 2
    elif i == 3:
        print 3
    elif i == 4:
        print 4
    elif i == 5:
        print 5
    elif i == 6:
        print 6
    elif i == 7:
        print 7
    elif i == 8:
        print 8
    elif i == 9:
        print 9

使用字典来解决更方便:

def get0():
    print 0
def get1():
    print 1
def get2():
    print 2
def get3():
    print 3
def get4():
    print 4
def get5():
    print 5
def get6():
    print 6
def get7():
    print 7
def get8():
    print 8
def get9():
    print 9

dict = {0:get0, 1:get1, 2:get2, 3:get3, 4:get4,
        5:get5, 6:get6, 7:get7, 8:get8, 9:get9}

while True:
    n = raw_input()
    i = int(n) % 10
    dict[i]()

字典的并集与交集

  • 对于字典:
a = dict.fromkeys(xrange(10))#dict.fromkeys来创建不考虑键对应的值
b = dict.fromkeys(xrange(5,15))

union = dict(a,**b)#交集
inter = dict.fromkeys(x for x in a if x in b)#并集
  • 对于集合:
a = set(xrange(10))
b = set(xrange(5,15))

union = a | b / union = a.union(b)#交集
inter = a & b / inter = a.intersection(b)#并集
  • 最好使用set类型而不是字典来代表集合。set能让代码更加直接、易读、清晰、高效。
  • 即使由于某些原因使用了dict,也应当尽可能地使用set来完成集合操作。如:你有个字典phones(人名映射到电话号码),还有个字典addresses(人名映射到地址),需要打印所有知道地址和电话号码的人名、电话号码、地址:
for name in set(phones) & set(addresses):
    print name,phones[name],addresses[name]

for name in set(phones).intersection(addresses):
    print name,phones[name],addresses[name]
#如果使用intersection方法,就不需要将两个字典都转化为set,只需要其中一个,然后再对转化后的set调用intersection,并传入另一个dict作为intersection方法的参数。

你可能感兴趣的:(Python)