将代码转换为漂亮的,地道的Python代码[操作指南,干货]
参考: Raymond Hettinger在PyCon US 2013上的演讲 Transforming Code into Beautiful, Idiomatic Python
立即改变
- 将传统的使用索引i的循环方式改变为python core的习惯方式
- 学习for-else语句,以及带有两个参数形式的iter()之类的高级技术
- 提升自己的技艺,并且追求干净、快速、地道的python代码
遍历一串顺序的数字:
for i in [0, 1, 2, 3, 4, 5]:
print i**2
for i in range(6):
print i**2
for i in xragne(6): #xrange是range的iter版
print i**2遍历一个数组:
colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)):
print colors[i]
for color in colors:
print color反向遍历:
colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)-1, -1, -1):
print colors[i]
for color in reversed(colors):
print color遍历同时获取索引编号:
colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)):
print i, '-->', colors[i]
for i, color in enumerate(colors):
print i, '-->', colors[i]遍历两个数组:
names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue', 'yellow']
n = min(len(names), len(colors))
for i in range(n):
print names[i], '-->', colors[i]
for name, color in zip(names, colors):
print name, '-->', color
for name, color in izip(names, colors): #izip是zip的iter版
print name, '-->', color遍历排序数组:
colors = ['red', 'green', 'blue', 'yellow']
for color in sorted(colors):
print color
for color in sorted(colors, reverse=True):
print color自定义排序:
colors = ['red', 'green', 'blue', 'yellow']
def compare_length(c1, c2):
if len(c1) < len(c2): return -1
if len(c1) > len(c2): return 1
return 0
print sorted(colors, cmp=compare_length) #compare_length在每次比较时都要调用,总次数为nlog(n)
print sorted(colors, key=len) #效率更高,只需调用n次循环遍历时在特定条件下调用函数:
blocks = []
while True:
block = f.read(32)
if block == '':
break
blocks.append(block)
blocks = []
#双参数的iter(),第二个参数是哨兵变量,一旦和哨兵变量相同就break
for block in iter(partial(f.read, 32), ''): #partial用于给read传递参数
blocks.append(block)区别出循环中的多个退出点
def find(seq, target):
found = False
for i, value in enumerate(seq):
if value == target:
found = True
break
if not found:
return -1
return 1
def find(seq, target):
for i, value in enumerate(seq): #使用for...else...
if value == target:
break
else:
return -1
return 1dict的技巧
- 熟练掌握dict是一项基础的python技能
- 这是一个基础的工具用于表达关系,连接,计数和分组
遍历dict的key
d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}
for k in d:
print k
for k in d.keys():
if k.startswith('r'):
del d[k]
d = {k : d[k] for k in d if not k.startswith('r')}遍历dice的key和value
for k in d:
print k, '-->', d[k]
for k, v in d.items():
print k, '-->', v
for k, v in d.iteritems(): #iteritems是items的iter版
print k, '-->', v通过pair创建dict
names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue']
d = dict(izip(names, colors))使用dict对list中元素计数
colors = ['red', 'green', 'red', 'blue', 'green', 'red']
d = {}
for color in colors:
if color not in d:
d[color] = 0
d[color] += 1
d = {}
for color in colors:
#使用get来减少了对元素是否存在的判断
d[color] = d.get(color, 0) + 1
d = defaultdict(int)
for color in colors:
d[color] += 1使用dict对list中元素分组
name = ['raymond', 'rachel', 'matthew', 'roger', 'betty', 'melissa', 'judith', 'charlie']
d = {}
for name in names:
key = len(name)
if key not in d:
d[key] = []
d[key].append(name)
d = {}
for name in names:
key = len(name)
d.setdefault(key, []).append(name)
d = defaultdict(list)
for name in names:
key = len(name)
d[key].append(name)提升可读性
- 位置或者索引参数是不错
- 但是使用keywords以及names更好
- 第一种方法对计算机来说很方便
- 第二种方式更适应人的思考
调用函数时使用参数名来传参使得表述更清晰
twitter_search('@obama', False, 20, True)
twitter_search('@obama', retweets=False, numtweets=20, popular=True)当函数返回多个值得时候请用named tuples
doctest.testmod()
(0,4)
doctest.testmod()
TestResults(failed=0, attempted=4)
TestResults = namedtuple('TestResults', ['failed', 'attempted'])Unpacking sequences
p = 'Raymond', 'Hettinger', 0x30, 'python@example.com'
fname = p[0]
lanme = p[1]
age = p[2]
email = p[3]
fname, lname, age, email = p同时更新多个变量
def fibonacci(n):
x = 0
y = 1
for i in range(n):
print x
t = y
y = x + y
x = t
def fibonacci(n):
x, y = 0, 1
for i in range(n):
print x
x, y = y, x+ytuple的packing和unpacking
- 不要低估这种同时改变变量的优点,这可以避免很多由于变量更新顺序造成的错误,尤其是在做一些迭代的数值运算的时候
tmp_x = x + dx * t
tmp_y = y + dy * t
tmp_dx = influence(m, x, y, dx, dy, partial='x')
tmp_dy = influence(m, x, y, dx, dy, partial='y')
x = tmp_x
y = tmp_y
dx = tmp_dx
dy = tmp_dy
x, y, dx, dy = (x + dx * t,
y + dy * t,
influence(m, x, y, dx, dy, partial='x'),
influence(m, x, y, dx, dy, partial='y'))字符串连接
names = ['raymond', 'rachel', matthew']
s = names[0]
for name in names[1:]:
s += ', ' + name
print s
print ', '.join(names)修改sequences
names = ['raymond', 'rachel', matthew']
del names[0]
names.pop(0)
names.insert(0, 'mark')
names = deque(['raymond', 'rachel', matthew'])
del names[0]
names.popleft()
names.appendleft('mark')Decorator和Context Managers
- 有利于拆分业务逻辑和控制逻辑
- 干净,漂亮的工具来分解代码以及提升代码复用
- 好的命名是最基本的
- 记住:能力越大责任越大
使用decorators来拆解出控制逻辑
def web_lookup(url, saved={}):
if url in saved: #控制逻辑
return saved[url]
page = urllib.urlopen(url).read() #业务逻辑
saved[url] = page
return page
def cache(func):
saved = {}
@wraps(func)
def newfunc(*args):
if args in saved:
return saved[args]
result = func(*args)
saved[args] = result
return result
return newfunc分解出临时的上下文环境
old_context = getcontext().copy()
getcontext().prec = 50
print Decimal(355) / Decimal(113)
setcontext(old_context)
with localcontext(Context(prec=50)):
print Decimal(355) / Decimal(113)如何打开和关闭文件
f = open('data.txt')
try:
data = f.read()
finally:
f.close()
with open('data'.txt') as f:
data = f.read()如何使用locks
# Make a lock
lock = threading.Lock()
# Old-way to use a lock
lock.acquire()
try:
print 'Critical section 1'
print 'Critical section 2'
finally:
lock.release()
# New-way to use a lock
with lock:
print 'Critical section 1'
print 'Critical section 2'分解出临时的上下文环境
try:
os.remove('somefile.tmp')
except OSError:
pass
with ignored(OSError):
os.remove('somefile.tmp')
# ignored的实现,在python 3.4中已支持
@contextmanager
def ignored(*exceptions):
try:
yield
except exceptions:
passwith open('help.txt', 'w') as f:
oldstdout = sys.stdout
sys.stdout = f
try:
help(pow)
finally:
sys.stdout = oldstdout
with open('help.txt', 'w') as f:
with redirect_stdout(f):
help(pow)
@contextmanager
def redirect_stdout(fileobj):
oldstdout = sys.stdout
sys.stdout = fileobj
try:
yield fileobj
finally:
sys.stdout = oldstdoutlist comprehensions 和 generator expressions
result = []
for i in range(10):
s = i ** 2
result.append(s)
print sum(result)
print sum([i ** 2 for i in range(10)])
print sum(i ** 2 for i in range(10))