前言

算来学会python已经4年有余, 使用它作为我的工作语言也3年了. 这个过程中我读过一些书, 看了很多人的博客.
也读了一些开源项目的代码, 但是尤其重要的是和同事在一起得到的进步. 一直到现在我都有习惯了解python, 提高自己的python能力

说到idiomatic. python有自己独特的语法和习惯. 而实现同样功能的代码不用的人呢也会使用不同的方式.
写出来的代码内容也有非常大的区别, 但是总是会有一个是更好的, idiomatic的写法. 今天突然翻到了一个我之前一直维护的keynote. 这里面记录了我总结和从其他的ppt或者代码里看到更优美的写法.
其中有些已经放在python3中, 说明这样的功能确实是程序员蛮有用的. 我整理了一下. 来给大家分享下.

PS: 这些是编程的思维, 举一反三, 再适合的时候利用上.

循环列表, 直到找到符合的结果, 没有结果返回一个默认值

通常这样:

1
2
3
4
5
6
a = -1
for i in range(1, 10):
if not i % 4:
a = i
break
# a = 4

更好的写法:

1
2
3
a = ''
a = next((i for i in range(1, 10) if not i % 4), -1)
# a = 4

执行调用直到某种情况

通常这样:

1
2
3
4
5
6
blocks = []
while True:
block = f.read(32)
if block == '':
break
blocks.append(block)

更好的写法:

1
2
3
4
from functools import partial
blocks = []
for block in iter(partial(f.read, 32), ''):
blocks.append(block)

标记区分

1
2
3
4
5
6
7
8
9
def find(seq, target):
found = False
for i, value in enumerate(seq):
if value == target:
found = True
break
if not found:
return -1
return i

更好的写法:

1
2
3
4
5
6
7
def find(seq, target):
for i, value in enumerate(seq):
if value == target:
break
else:
return -1
return i

threading.Lock

1
2
3
4
5
6
7
8
lock = threading.Lock()
lock.acquire()
try:
print 'Critical section 1'
print 'Critical section 2'
finally:
lock.release()

其实是这样的:

1
2
3
4
5
lock = threading.Lock()
with lock:
print 'Critical section 1'
print 'Critical section 2'

忽略抛出的异常

1
2
3
4
try:
os.remove('somefile.tmp')
except OSError:
pass
1
2
with ignored(OSError):
os.remove('somefile.tmp')

就算用python2, 我也强烈建议把这样的函数放在项目里

1
2
3
4
5
6
@contextmanager
def ignored(*exceptions):
try:
yield
except exceptions:
pass

如果你使用python3.4或以上可以使用标准库的 contextlib.suppress

1
2
3
4
5
6
7
class suppress:
def __init__(self, *exceptions):
self._exceptions = exceptions
def __enter__(self):
pass
def __exit__(self, exctype, excinst, exctb):
return exctype is not None and issubclass(exctype, self._exceptions)

直接把输出存进文件中

1
2
3
4
5
6
7
with open('help.txt', 'w') as f:
oldstdout = sys.stdout
sys.stdout = f
try:
help(pow)
finally:
sys.stdout = oldstdout

同样使用python3.4以上可以使用

1
2
3
with open('help.txt', 'w') as f:
with redirect_stdout(f):
help(pow)

redirect_stdout是这样的:

1
2
3
4
5
6
7
8
@contextmanager
def redirect_stdout(fileobj):
oldstdout = sys.stdout
sys.stdout = fileobj
try:
yield fieldobj
finally:
sys.stdout = oldstdout

最简单的缓存

通常这样实现缓存:

1
2
3
4
5
6
def web_lookup(url, saved={}):
if url in saved:
return saved[url]
page = urllib.urlopen(url).read()
saved[url] = page
return page

可以这样写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@cache
def web_lookup(url):
return urllib.urlopen(url).read()
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