Garland +

My Own Python Cookbook

对列表/元组计数

情景:现在有一个列表/元组,里面有重复元素,需要统计出来 一般情况下,我们可能会这样子写:

#统计
def get_counts(sequence):
    counts = {}
    for x in sequence:
        if x in counts:
            counts[x] += 1
        else:
            counts[x] = 1
    return counts
#排序
def top_counts(counts,n=10):
    value_key_pairs = [(number, name) for name, number in counts.items()]
    value_key_pairs.sort()
    return value_key_pairs[-n:]

Python标准库中有一个collections.Counter类,可以简化上面的代码:

from collections import Counter

counts = Counter(sequence)
counts.most_common(10)

在Class里面使用map的问题

会经常用到map来编写简单的多进程的程序,一般情况下,这样写是没有问题的:

import multiprocessing as mul

def f(x):
    return x**2

def run():
    pool = mul.Pool(4)
    print pool.map(self.f,range(10))

run()

可是将该方法写进类里面就会报错:

import multiprocessing as mul

class deal():
    def f(self,x):
        return x**2

    def run(self):
        pool = mul.Pool(4)
        print pool.map(f,range(10))

m = deal()
m.run()
#PicklingError:" Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed "

搜了一圈,只有把函数f()当作参数传进类里面才可以:

import multiprocessing as mul

def f(x):
    return x**2

class deal():
    def __init__(self,func):
        self.f = func

    def run(self):
        pool = mul.Pool(4)
        print pool.map(self.f,range(10))

m = deal(f)
m.run()

不过python3已经解决的了这个问题,就不用纠结了。这里这里稍微讲了下。

优雅地获取序列迭代的索引和值

使用enumerate(),每次只在需要的時候才会产生一个(index,item)对;而且,序列可以是list,set也可以是任何可迭代的对象。

li = [3,7,4,3,2,6,8]
for i,e in enumerate(li):
    print 'index:',i,'ele:',e

#逆序
for i,e in enumerate(li[::-1]):
    print 'index:',i,'ele:',e

但是字典的话,enumerate()会将字典转换成序列处理。所以对于字典,应该使用iteritems()方法

info = {'name':'Bob','age':'18','tel':'8879654'}
for i,e in info.iteritems():
    print i,':',e

while 1 VS while True

在python2中,True不是一个关键字,它是一个布尔型的全局常量,运行的时候,python解释器会把1赋给True.所以在python2中,一个很奇怪的现象 True = False 是成立的,也就是说,True是可以被赋值的。但是在python3中,True就成了关键字了.

所以,答案出来了。在python2中,尽量使用while 1,在python3中就无所谓了。

python在终端输出彩色内容

平时写脚本会有需要在终端输出彩色的日志以提高可读性。其实这个和python是没有关系啦,终端字符颜色是通过转义序列控制的,属于系统在文本模式下的显示功能,转义序列是以ESC开头,也就是ESC的ASCII码,比如用八进制表示的033。格式如下

\033[显示方式;前景色;背景色m
#比如python,输出高亮的绿色morning
print '\033[1;32mMorning'

在这里给一张图,来自这里,肯定是够用的了

彩色代码

Requests库处理中文乱码

在处理中文网页的时候使用requests.get(url).text有时候会产生乱码,比如我在爬bilibili的时候就出现了。因为requests库会自己推测服务器的文本编码,并自动处理,所以有时候会出现乱码,requests.get(url).content方法返回的是requests库处理之前的内容,这样就能显示正确的文字了。

and or 以及 and-or

在python中and和or这两个逻辑运算符执行后并不返回布尔值,返回的是他们比较值之一

列表删除元素方法的区别

is ==

python在这块儿确实比较比较难理解,因为互相都有关联,所以就放在一块儿了

首先是is和==的区别:is表示的是对象表示符,也就是判断两个对象在内存中是否拥有同一块内存空间,x is b相当于id(x)==id(y). 而==表示的是两个对象的是否相等,它调用的是内部的__eq__()方法。一般情况下,x is y为True的话,x==y也为True,给张图说话: is_equal 从图上看,列表是没问题的,但是两组字符串为什么结果不一样。这是由python中的字符串驻留机制所决定的:对于较短的字符串,为了提高性能 会保留其值的一个副本,创建新的字符串时会直接指向那个副本,所以c和d的id值是一样的;但是d和e都是长字符串了, 不会驻留,所以会在内存中各自创建对象来保存e和f。

可变对象的一些陷阱

上面说了is和==的区别,趁热再来说一下可变对象的一些陷阱,这里就用list讲,再给张图说话: is_equal 首先a引用了一个列表对象,赋值b=a的话,两个变量都会引用同一个对象,同时这个对象又是可变的,所以对任何 一个别名(一个对象有多个引用,并且引用有不同名称时,就说这个对象有别名)的修改都会影响到另一个。

但是,对列表+和切片操作会新建一个列表,而append会在原列表上操作。要添加一个元素的话a.append(9)和 a = a + [9]都是正确的(区别是第二种方法a的id会变的),但是a.append([9])是错的这个很容易看出来,但是 为什么a = a.append(9)也是错的呢?因为大部分列表方法都是修改参数并返回None的,append也不例外, 所以比如要给列表排序的时候可以先对列表做一个0切片保留副本,再使用列表的sort方法,或者使用sorted会返回一个新的 排好序的列表,不过平时还是推荐使用sorted啦。

浅拷贝和深拷贝

先上一张图说话: copy1 现在你想修改一个对象,而且不想让原始对象收到影响,所以需要对象复制,切片、copy.copy()、或者list()都可以完成, 就像a和b一样,确实变了,但是对于对象中的元素,id依然是一样的,这种的就是浅拷贝了。

然后再说下对可变元素和不可变元素的修改,在图中,b2=9,因为数字是不可变对象,所以修改的话会创建一个新的对象, 而对于b[3]列表是可变对象,所以当b[3][0]=0的时候,就会在id(b[3])的位置上做修改,所以a[3]和b[3]都会变的, 那要是不想这样怎么办?再来一张图: copy2 标准库copy的deepcopy方法,可以复制一个对象所有元素以及它的子元素,这样就是深拷贝了, 虽然会消耗时间和空间但是是完全复制的唯一方法。看图中,对于数字、字符串、元组这些不可变对象,因为不论 浅拷贝还是深拷贝,都会创建一个新的对象,但是又不能保证用户会对每个对象做修改,所以会保持不变以提高性能(这个是我猜的) 而对于列表,字典这些可变对象,要达到深复制的目的,只能创建一个新的对象。就酱~

Flask带用户数据调试

之前写代码调试的时候,有些数据需要用户登陆这个行为才能拿到,直接调用login(user)的话,会出现working outside of application context这种错误, 需要这样

with app.test_request_context():
    login(user)
    # do something

Git本地分支与远端同步

python取反操作符的

来源

Blog

Thoughts

Project