让 Python 代码变得 Pythonic

2017/04/11 Python

Pythonic是一个经常被Python程序员提及的关键词,它用来形容符合Python风格的代码,让我们的代码变得更加直观、简洁、可读,甚至能提高我们代码的运行效率。这篇文章就让我们通过一些例子来学学Pythonic。

本文开头,我们先介绍一个Python库——pep8,它可以用来检测我们的代码是否符合Pythonic风格,用pip可以直接安装,要看一个文件是否符合Pythonic,只要运行pep8 MyPython.py就可以了。通过这种方式,我们可以迅速地习惯Pythonic这种Python编程风格。接下来我们再看一些比较直观的例子:

交换两个值

# 常规写法
t = a
a = b
b = t

# 糟糕写法
a = a ^ b
b = a ^ b
a = b ^ a

# Pythonic写法
a, b = b, a

连接字符串

# 常规写法
a += b

# Pythonic写法
a.join(b)

迭代输出序号

# 常规写法
index = 0
for item in iterable:
    print index, item
    index += 1

# Pythonic写法
for index, item in enumerate(iterable):
    print index, item

index = 100
for item in iterable:
    print index, item
    index += 1

# Pythonic写法
for index, item in enumerate(iterable, 100):
    print index, item

同时迭代

# 常规写法
for pos in xrange(len(iterable1)):
    item1 = iterable1[pos]
    item2 = iterable2[pos]
    print item1, item2

# Pythonic写法
for item1, item2 in zip(iterable1, iterable2):
    print item1, item2

求幂

# 常规写法
x = pow(2, 20)

# Pythonic写法
x = 2 ** 20

级联比较

# 常规写法
a, b, c = 1, 2, 3
if a < b and b < c:
    pass

# Pythonic写法
a, b, c = 1, 2, 3
if a < b < c:
    pass

字符串格式化

# 常规写法
name = 'xxx'
age = 21
string = 'My name is %s and I am %d years old' % (name, age)

# Pythonic写法
string = 'My name is {name} and I am {age} years old.'.format(name='xxx', age=21)

装饰器

假设我们有一个类,要求这个类中的函数执行的时候都要顺带输出函数的名称,那么我们可以这样写:

class Person(object):
    def sleep(self):
        print("{name}".format(name=func.__name__))
        print("sleeping...")

    def eat(self):
        print("{name}".format(name=func.__name__))
        print("eating...")

person = Person()
person.sleep()
person.eat()

但是这样写的话,当函数变多的时候,我们就要对print("{name}".format(name=__name__))这行代码多次复制粘贴,针对这个问题,Python提供了装饰器,具体使用如下:

def log(func):
    def wrapper(*args, **kw):
        print("{name}".format(name=func.__name__))
        return func(*args, **kw)
    return wrapper


class Person(object):
    @log
    def sleep(self):
        print("sleeping...")

    @log
    def eat(self):
        print("eating...")

person = Person()
person.sleep()
person.eat()

如果我们需要传参数给装饰器,则需要修改代码如下:

def log(action):
    def decorator(func):
        def wrapper(*args, **kw):
            print("{action}".format(action=action))
            return func(*args, **kw)
        return wrapper
    return decorator


class Person(object):
    @log("sleep")
    def sleep(self):
        print("sleeping...")

    @log("eat")
    def eat(self):
        print("eating...")

person = Person()
person.sleep()
person.eat()

对于以上代码,person.eat()实际上等价于eat = log("eat")(eat),也就是最后eat变成了wrapper(可以打印eat的函数名称查看),明显不符合我们的设计理念,对于这个问题,python提供了functools这个工具库帮我们解决,具体如下:

import functools


def log(action):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print("{action}".format(action=action))
            return func(*args, **kw)
        return wrapper
    return decorator


class Person(object):
    @log("sleep")
    def sleep(self):
        print("sleeping...")

    @log("eat")
    def eat(self):
        print("eating...")

person = Person()
person.sleep()
person.eat()
print(person.sleep.__name__)
print(person.eat.__name__)

Search

    Table of Contents