1. Python判断值是否为空
代码中经常会有变量是否为None的判断,有三种主要的写法:
第一种是:if x is None
第二种是:if not x
第三种是:if not x is
None`(这句这样理解更清晰`if not (x is None)`) 。`if x is not None`是最好的写法,清晰,不会出现错误,以后坚持使用这种写法。使用if not x这种写法的前提是:必须清楚x等于None, False, 空字符串””, 0, 空列表[], 空字典{}, 空元组()时对你的判断没有影响才行。
foo is None 和 foo == None的区别,如果比较相同的对象实例,is总是返回True 而 == 最终取决于 “eq()”==只要相等,is表明要一样,同一个对象
2. 三元运算符运用
三元运算符通常在Python里被称为条件表达式,这些表达式基于真(true)/假(false)的条件判断,在Python 2.4以上才有了三元操作。
1 |
condition_is_true if condition else condition_is_false #如果条件为真,返回真,否则返回假 |
代码如下:
1 2 3 4 5 6 7 |
>>> is_fat = True >>> state = "fat" if is_fat else "not fat" >>> state 'fat' >>> state = "fat" if not is_fat else "not fat" >>> state 'not fat' |
它允许用简单的一行快速判断,而不是使用复杂的多行if语句。 这在大多数时候非常有用,而且可以使代码简单可维护。比如下面在Django开发中从数据库取数据,如果userinfo对象没有值那么userinfo.permissions必然会抛异常,这里就可以简单使用三元运算符处理。
1 2 |
userinfo = account.objects.filter(username=user) permission=userinfo.permissions if userinfo else '' |
3. 字典合并
Python中将两个字典或多个字典进行合并操作,是一个比较常见的问题。下面介绍几种实现两个字典合并的方案。
在Python 2.x版本时,你可能会使用下面这种笨方法:
1 2 3 4 |
>>> dictMerged = dict1.copy() >>> dictMerged.update( dict2 ) >>> dictMerged {'a': 'aa', 'b': 'bb'} |
对于第一步的复制操作而言,这种使用内建方法copy()的复制方式,和方法2中的复制结果是一样的,但根据《Core Python Programming (2nd edition)》一书中7.3.2节所述,从已存在字典中生成新字典的方式dictNew = dict( dictOld )较内建方法dictNew = dictOld.copy()会慢一些,因此书中推荐使用copy()方法。
在Python 3中,提供了参数解包特性,这是Python 3.5添加的新特性(PEP 448),使得*a
、**d
可以在函数参数之外使用:
1 2 3 4 5 6 7 8 9 10 |
>>> print(*range(5)) 0 1 2 3 4 >>> lst = [0, 1, 2, 3] >>> print(*lst) 0 1 2 3 >>> d = {"hello": "world", "python": "rocks"} >>> print({**d}["python"]) rocks |
所谓的解包(Unpacking)实际上可以看做是去掉()的元组或者是去掉{}的字典。这一语法也提供了一个更加 Pythonic 地合并字典的方法:
1 2 3 |
>>> dictMerged = {**dict1, **dict2} >>> dictMerged {'a': 'aa', 'b': 'bb'} |
一般会使用dict()工厂方法替代{}使用:
1 |
>>> dict(**dict1, **dict2) |
允许接受字典或关键字参数字典进行调用。但应当注意,对于这种调用方式,dict()最多只接受一个参数(或者说是一组name=value的可变长参数),如下:
1 2 3 4 5 |
>>> dict(dict1) {'a': 'aa'} >>> dict(dict1=dict1, dict2=dict2) {'dict1': {'a': 'aa'}, 'dict2': {'b': 'bb'}} |
但dict()不会接受大于1个字典,因此直观上的简单使用dict1与dict2两个参数的方法会提示如下错误:
1 2 3 4 |
>>> dict(dict1, dict2) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: dict expected at most 1 arguments, got 2 |
4. 列表解析式
列表解析式也称之为列表推导式,即List Comprehensions,是Python内置的非常简单却强大的可以用来创建列表的生成式。本质上就是用列表来构建列表,通过对已有列表中的每一项应用一个指定的表达式来构建出一个新的列表。列表解析式的优势是编码简单,运行起来很快。
列表解析式的三个核心要素是:
1. 作用于输入序列的运算表达式;
2. 对输入序列的循环表达式;
3. 对输入序列的过滤条件,其中过滤条件是可选的。
举个例子,要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用list(range(1, 11)):
1 2 |
>>> list(range(11)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
但如果要生成[1×1, 2×2, 3×3, …, 10×10]怎么做?方法一是循环:
1 2 3 4 5 6 |
>>> L = [] >>> for x in range(1,11): ... L.append(x * x) ... >>> L [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] |
但是循环太繁琐,且效率不高。而解析式则可以用一行语句代替循环生成上面的list:
1 2 3 4 5 |
>>> [x for x in range(1, 11)] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> [x * x for x in range(1, 11)] [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] |
写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来,十分有用,多写几次,很快就可以熟悉这种语法。
for循环后面还可以加上if判断,起到过滤的作用,比如我们可以仅筛选出偶数的平方:
1 2 |
>>> [x * x for x in range(1, 11) if x % 2 == 0] [4, 16, 36, 64, 100] |
虽然用列表表达式表示出这段代码很短,但是其可读性确实很糟糕。关于列表解析式更多用法参考“Python列表解析式”。
5. 列表去重
在某些情况下,我们可能需要把列表里面的元素进行去重处理。常用的大概有这么几种方法。
- 常规处理
1 2 3 4 5 6 7 |
ids = [1,2,3,1] news_ids = [] for id in ids: if id not in news_ids: news_ids.append(id) print(news_ids) |
思路看起来比较清晰简单 ,也可以保持之前的排列顺序。
- 通过SET方法进行处理
1 2 |
ids = [1,2,3,1] ids = list(set(ids)) |
处理起来比较简单,使用了集合方法set进行处理,不过结果不会保留之前的顺序。
- 利用lambda匿名函数和reduce函数处理
1 2 3 |
ids = [1,2,3,1] func = lambda x,y:x if y in x else x + [y] reduce(func, [[], ] + ids) |
- 利用循环处理
1 2 3 4 5 |
def delRepeat(l): for x in l: while l.count(x)>1: del l[l.index(x)] return l |
一种取巧的方式。