学过C或C++的人再学python,写出的代码难免会保留C/C++的风格,而看起来没有那么Pythonic。
Python代码的风格实际上是非常简洁的,以最少的代码量写出完整的功能
本文为博主总结的一些帮助我们写出更加Pythonic代码的技巧
Table of Contents
- 1 变量交换
- 2 元素遍历
- 3 字符串连接
- 4 上下文管理器
- 5 使用生成式
- 6 使用装饰器
- 7 使用 collections 库
- 8 序列解包
- 9 遍历字典 key 和 value
- 10 链式比较操作
- 11 if else 三目运算
- 12 真值判断
- 13 for else 语句
- 14 字符串格式化的8种方法
- 15 切片
- 16 使用生成器
- 17 获取字典元素的 get 方法
- 18 预设字典返回的默认值
- 19 函数参数 unpack
- 20 注意函数默认参数
- 21 为 dict 添加
__missing__
方法 - 22 python 解释器中的 _
- 23 try/except/else
- 24 print 重定向输出到文件
- 25 省略号
- 26 pow 还有第三个参数
- 27 isinstance 可以接收一个元组
- 28 字典的无限递归
- 29 Python 可以认识 Unicode 中的数字
- 30 不能访问到的属性
- 31 使用计数器对象进行计数
- 32 漂亮的打印 JSON
- 33 字典的剧本
- 34 无限循环的结束
- 35 序列乘法
- 36 显示循环进度条
- 37 Other-Trick
# 让 notebook 输出所有单行变量
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
变量交换¶
python 中交换两个变量不需要引入临时变量
a, b = 1, 2
a, b
a, b = b, a
a, b
自然想到三个变量的交换
a, b, c = 1, 2, 3
a, b, c
a, b, c = c, a, b
a, b, c
元素遍历¶
普通的遍历,类似其他语言中的 for each 或是基于范围的 for 循环
for i in range(5):
print(i)
使用 enumerate 进行带索引的容器遍历
colors = ['red', 'green', 'blue', 'yellow']
for index, color in enumerate(colors):
print('{}, {}'.format(index, color))
事实上,enumerate 还接受第二个参数,用于指定 index 的起始位置,默认为 0
list(enumerate(colors, 1))
字符串连接¶
经常使用的 字符串连接方法有三种,join, format 和 + 操作符 在需要连接的字符串个数较少的情况下,+ 效率较高,随着个数的增加,join 的优势会更大
names = ['raymond', 'rachel', 'matthew', 'roger',
'betty', 'melissa', 'judith', 'charlie']
print(', '.join(names))
上下文管理器¶
fr = open('data/dataa.txt', 'w')
fr.write('x')
fr.close()
with open('data/test.txt') as f:
data = f.read()
print(data)
使用生成式¶
最常见的是列表推导式
[2*i for i in range(10)]
其次还有:集合推导式和字典推导式,原先在 python2 版本中的 set 是需要通过 set 函数来显示转换的,但后来 python3 中直接进行 set 推导的语法也被移植到了 python2 中。不过要注意的是 () 定义的不是元组推导式而是生成器
numbers = [1, 2, 3]
my_dict = {number: number * 2 for number in numbers if number > 1}
my_dict
推导式可以嵌套,而且可以加入一定的条件机制,各个条件之间的关系是 与
[(x, y)
for x in range(10)
for y in range(10)
if x + y == 5
if x > y]
甚至可以利用列表生成式来实现快速排序,非常优雅,但是对于一般我们写排序算法尽量进行要原址排序
def quicksort(lst):
if len(lst) == 0:
return []
else:
return quicksort([x for x in lst[1:] if x < lst[0]]) + [lst[0]] + \
quicksort([x for x in lst[1:] if x >= lst[0]])
quicksort([2, 3, 5, 1, 6, 9, 8, 3]) # 使用装饰器
使用装饰器¶
import time
from functools import wraps
def timethis(func):
'''
函数计时
'''
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(func.__name__, end-start)
return result
return wrapper
# 下面我们使用这个被包装后的函数并检查它的元信息:
@timethis
def countdown(n):
'''
Counts down
'''
while n > 0:
n -= 1
countdown(100000)
使用 collections 库¶
deque
from collections import deque
names = deque(['raymond', 'rachel', 'matthew', 'roger',
'betty', 'melissa', 'judith', 'charlie'])
names.popleft()
names.appendleft('mark')
names
deque 还具有 maxlen 关键字参数,可以限制其最大容量
letters = deque(['a', 'b', 'c', 'd', 'e'], maxlen=5)
letters
letters.append('f')
letters
序列解包¶
p = 'vttalk', 'female', 30, 'python@qq.com'
name, gender, age, email = p
另外可以用 *somename
来接收不需要的一大段值
name, *middle, email = p
name, middle, email
遍历字典 key 和 value¶
d = {'a': 1, 'b': 2, 'c': 3}
for k, v in d.items(): # python2 有 iteritems 方法,但在 python3 中已经被移除
print(k, '--->', v)
链式比较操作¶
age = 59
18 < age < 60
False == False == True # 等价于 (False == False) == (False == True)
if else 三目运算¶
gender = 'female'
text = '男' if gender == 'male' else '女'
text
真值判断¶
很多情况下 不需要使用 == 和 != 去比较真假
values = object
if values:
print('haha')
真假值对照表
类型 | False | True |
---|---|---|
bool | False | True |
str | '' | 非空str |
数值 | 0,0.0 | 非0数值 |
容器 | [],(),{},set() | 非空容器 |
None | None | 非None对象 |
以下为几条 and or 的替代写法
判断诸多条件是否至少有一个成立¶
math, physics, computer = 40, 60, 70
if any([math < 60, physics < 60, computer < 60]):
print("Not Pass")
或的另一种写法¶
i, a, b = 1, 2, 3
# way 1
if i == a or i == b:
print('yes')
# way 2
if i in (a, b):
print('yes')
判断诸多条件是否全部成立¶
math, physics, computer = 61, 60, 70
if all([math >= 60, physics >= 60, computer >= 60]):
print("Pass")
for else 语句¶
除非 break 否则 else 语句是一定会执行的
mylist = [0, 1, 2, 3]
for i in mylist:
if i == 4:
break # 跳出整个 for else 循环
print(i)
else:
print('oh yeah')
字符串格式化的8种方法¶
推荐使用 format 或 fstring
1.+号连接
stra, strb = "Hello", "World"
stra + strb
2.在print中使用,连接
print(stra, strb)
3.直接连接
print('hello' 'world')
print('hello''world')
这实际上是Python的一个语法糖,连接的字符串会自动拼接为一个字符串
import dis
def func():
strr = 'a''b'
dis.dis(func)
4.% 格式化
在 Python 2.6 以前,%操作符是唯一一种格式化字符串的方法,它也可以用于连接字符串
print('%s %s' % (stra, strb))
5.format 函数
format 方法是 Python 2.6 中出现的一种代替 % 操作符的字符串格式化方法,同样可以用来连接字符串。
print('{} {}'.format(stra, strb))
6.join 函数
字符串的内置方法
print('-'.join([stra, strb]))
f-string
Python 3.6 中引入了 Formatted String Literals(字面量格式化字符串),简称 f-string,f-string 是 % 操作符和 format 方法的进化版,使用 f-string 连接字符串的方法和使用 %操作符、format 方法类似。
f'{stra} {strb}'
8.*
号
stra * 3
实际上对应 __mul__
魔法方法
stra.__mul__(3)
items = list(range(10))
items[0:4]
items[1::2]
items[::] # 浅拷贝
items[:] # 浅拷贝
使用生成器¶
def fib(n):
a, b = 0, 1
while a < n:
yield a
a, b = b, a + b
gen = fib(5)
for i in gen:
print(i)
Python 3 中的 next 方法变为 next 函数
一个实例化的生成器在迭代完后便不可再使用,即只能迭代使用一次
try:
next(gen)
except Exception as e:
print(e)
gen = fib(3)
next(gen)
next(gen)
获取字典元素的 get 方法¶
当 key 不存在时即返回默认值
d = {'name': 'foo'}
d.get("namey", "unknown")
预设字典返回的默认值¶
当 key 不存在时即返回默认值
第一种方式 setdefault
data = {('a', 1), ('b', 2), ('a', 3)}
groups = {}
for (key, value) in data:
groups.setdefault(key, []).append(value)
groups
第二种方式 defaultdict 库
from collections import defaultdict
groups = defaultdict(list)
for (key, value) in data:
groups[key].append(value)
groups
函数参数 unpack¶
本质上就是容器/可迭代对象的解包
def foo(x, y):
print(x, y)
alist = [1, 2]
adict = {'x': 1, 'y': 2}
foo(*alist)
foo(**adict)
注意函数默认参数¶
def foo(x=[]):
x.append(1)
print(x)
foo()
foo()
更安全的做法
def foo(x=None):
if x is None:
x = []
x.append(1)
print(x)
foo()
foo()
为 dict 添加 __missing__
方法¶
class Dict(dict):
def __missing__(self, key):
self[key] = []
return self[key]
dct = Dict()
dct["foo"].append(1)
dct["foo"].append(2)
dct["foo"]
dct["bar"]
这种行为很像 collections.defaultdict
from collections import defaultdict
dct = defaultdict(list)
dct["foo"] # 对不存在的 key 进行访问或自动创建空容器
dct["bar"].append("Hello")
dct
python 解释器中的 _¶
用于获取上一次的对象
list(range(4))
_
Zen of Python
import this
try/except/else¶
try:
Normal execution block
except A:
Exception A handle
except B:
Exception B handle
except:
Other exception handle
else:
if no exception,get here
finally:
print("finally")
try:
print(parrot)
except NameError:
print("'E's pining!")
else:
print("This parrot is no more!")
finally:
print('done')
print 重定向输出到文件¶
# Python 3 已移除
# print >> open("somefile", "w+"), "Hello World"
省略号¶
...
pow 还有第三个参数¶
pow 还接受第三个参数,用来求模
pow(x, y, z) == (x ** y) % z
pow(4, 2, 2)
isinstance 可以接收一个元组¶
元组内的类型是或的关系
isinstance("1.3", (float, int))
isinstance("1.3", (int, float, str))
字典的无限递归¶
a, b = {}, {}
a['b'] = b
b['a'] = a
a
a, b = [], []
a.append(b)
b.append(a)
a
Python 可以认识 Unicode 中的数字¶
int(u'1234')
不能访问到的属性¶
class O(object):
pass
o = O()
setattr(o, "can't touch this", 123)
这个属性是访问不到的,因为 '
的存在,不过,能用 setattr 设置属性,自然就可以用 getattr 取出
使用计数器对象进行计数¶
这是 collections 库中的一个 dict 子类,专门用于解决计数问题, 子类还包括 most_common 等方法
from collections import Counter
c = Counter('hello world')
c
c.most_common(2)
漂亮的打印 JSON¶
使用 indent 关键字参数即可偏亮的打印 JSON
import json
data = {'a': 1, 'b': 2}
print(json.dumps(data))
print(json.dumps(data, indent=2))
dct = {'a': 1}
# 不推荐
# dct.has_key('a') Python 3 移除
# 推荐
'a' in dct
无限循环的结束¶
# 不推荐
file = open("data/dataa.txt", "r")
while 1: # infinite loop
line = file.readline()
if not line: # 'readline()' returns None at end of file.
break
print(line)
file.close()
file = open("data/dataa.txt", "r")
# 推荐
for line in file:
print(line)
file.close()
# 更好 使用上下文管理器
with open('data/dataa.txt', 'r') as f:
for line in f:
print(line)
open 函数的功能也可由 file 替代
序列乘法¶
[0] * 2
' ' * 2
显示循环进度条¶
import time
N = 100
for i in range(N+1):
time.sleep(0.01)
if i % 10 == 0:
print(i, end="\r")
进阶版
import sys
import time
def progress_bar(num, total):
rate = num/total
pecent = int(100*rate)
r = "\r[{}{}]{}%".format("*"*pecent, " "*(100-pecent), pecent)
sys.stdout.write(r)
sys.stdout.flush()
for i in range(N+1):
time.sleep(0.01)
progress_bar(i, N)
Other-Trick¶
Jupyter Notebook 中获取函数帮助¶
光标移动至函数名右侧(或选中函数名),按住Shift + Tab键弹出帮助文本框
修改多处的同一标识符名字¶
按住Ctrl鼠标移动光标同时选中多处编辑位置,启动多行编辑