前言

算来学会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