前言

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

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

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

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

通常这样:

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

更好的写法:

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

执行调用直到某种情况

通常这样:

blocks = []
while True:
    block = f.read(32)
    if block == '':
        break
    blocks.append(block)

更好的写法:

from functools import partial
blocks = []
for block in iter(partial(f.read, 32), ''):
    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 i

更好的写法:

def find(seq, target):
    for i, value in enumerate(seq):
        if value == target:
            break
    else:
        return -1
    return i

threading.Lock

lock = threading.Lock()
lock.acquire()

try:
    print 'Critical section 1'
    print 'Critical section 2'
finally:
    lock.release()

其实是这样的:

lock = threading.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')

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

@contextmanager
def ignored(*exceptions):
    try:
        yield
    except exceptions:
        pass

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

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)

直接把输出存进文件中

with open('help.txt', 'w') as f:
    oldstdout = sys.stdout
    sys.stdout = f
    try:
        help(pow)
    finally:
        sys.stdout = oldstdout

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

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

redirect_stdout 是这样的:

@contextmanager
def redirect_stdout(fileobj):
    oldstdout = sys.stdout
    sys.stdout = fileobj
    try:
        yield fieldobj
    finally:
        sys.stdout = oldstdout

最简单的缓存

通常这样实现缓存:

def web_lookup(url, saved={}):
    if url in saved:
        return saved[url]
    page = urllib.urlopen(url).read()
    saved[url] = page
    return page

可以这样写

@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