优雅的 Python

Python 语法简洁干净,但为了写出 Pythonic 代码,还需要一些经验和技巧。笔者根据网络博文整理了一份学习资料,贴出来与大家分享。

参考

1. 代码这样写不止于优雅(Python版) – 推酷

2. http://python.jobbole.com/86808/

3. Python 有哪些优雅的代码实现?让自己的代码更pythonic

基础语法

# 尽可能少地引入变量
a, b = b, a	# 变量交换

# 赋值技巧
colors = 'red', 'green', 'blue', 'yellow'
red, green, blue, yellow = colors	# 适用于列表、元组等

# 字符串格式化
s = "Welcome to {blog} and following {wechat}".format(blog="Windrivder.me", wechat="Windrivder")

# 字符串连接
colors = ['red', 'green', 'blue', 'yellow']
print('- '.join(colors))	# join() 在内存中只会产生一个字符串对象

# if/else 三目运算
text = '男' if gener == 'male' else '女'

# for/else 语句
for i in mylist:
    pass
else:	# else 会在 for 循环遍历结束后执行
    pass

# 链式比较
age = 19
if 18 < age < 60:
    print('Youg man')

# 判断真值
if arr:
    do_something()
if values:
    do_something()

《优雅的 Python》
《优雅的 Python》

列表

# 列表推导式
[i * 2 for i in range(6)]	# 可以取代 map 和 filter
# 同时列表推导式会消耗大量内存,数据多时建议使用生成器表达式
list = (x ** 2 for x in range(0, 100000))

# list 是一个查询效率高于更新操作的数据结构,可适当考虑使用双向队列
from collections import deque
names = deque(['Jack', 'King', 'Betty', 'Windrivder'])	# 双向队形
names.popleft()
names.appendleft('Hello')

# 切片
items = range(10)
sub_items = items[1:4] # list[start:end:step]
odd_items = items[1::2]
copy_items = items[:] # 复制
reverse_items = items[::-1]	# 反序
item = items[0:-1]
--------------------------
 | P | y | t | h | o | n |
--------------------------
   0   1   2   3   4   5 
  -6  -5  -4  -3  -2  -1
--------------------------

字典

# 获取字典元素
d = {'name': 'windrivder'}
d.get('name', 'jack')	# 第二个参数设置默认值

# 预设字典默认值
data = [('foo', 10), ('bar', 20), ('foo', 39), ('bar', 49)]
groups = {}
for (key, value) in data:	# 方式一
    groups.setdefault(key, []).append(value)

from collections import defaultdict	# 方式二
groups = defaultdict(list)
for (key, value) in data:
    groups[key].append(value)
    
# 字典推导式
numbers = [1, 2, 3]
my_dict = {number: number * 2 for number in numbers}
my_dict = {number: number * 2 for number in numbers if number > 1}

# 遍历字典的 key 和 value
for k, v in d.items():
    print(k, '-->', v)

生成器

# 生成器比列表更加节省内存
for i in range(6):
    print(i)

# 生成器无需一次性加载所有元素到内存
def fib(n):
    a, b = 0, 1
    while a < n:
        yield a
        a, b = b, a + b
l = [i for i in fib(10)] # 列表会一次性把全部元素加载到内存中

遍历

# 带有索引位置的集合遍历
colors = ['red', 'green', 'blue', 'yellow']
for i, color in enumerate(colors):	# 传入第二个参数时迭代时加在 index 上的数值
    print(i, '-->', color)

# 用 zip 同时遍历两个迭代器
list_a = ['a', 'b', 'c', 'd']
list_b = [1, 2, 3]
for letter, number in zip(list_a, list_b):
    print(letter, number)	# 只要有一个列表耗尽,迭代就会停止
    
# zip 遍历时返回一个元组
a = [1, 2, 3]
b = ['w', 'x', 'y', 'z']
for i in zip(a, b):
    print(i)

list_example = [i for i in range(5)]
iter_example = (i for i in range(5)) # 迭代器
set_example = {i for i in range(5)} # 集合

for i in reversed(list_example):	# 只能迭代 list,无法作用于集合和迭代器
    print(i)
    
# 反向迭代还可以在类里的 __reversed__ 方法实现
class Countdown:
    def __init__(self, start):
        self.start = start
    # 正向迭代
    def __iter__(self):
        n = self.start
        while n > 0:
            yield n
            n -= 1
    # 反向迭代
    def __reversed__(self):
        n = 1
        while n <= self.start:
            yield n
            n += 1

装饰器

# 利用装饰器将与业务逻辑无关的代码抽离出来,同时可以在多个地方重复利用
def web_lookup(url, saved={}):
    if url in saved:
        return saved[url]
    page = urllib.urlopen(url).read()
    saved[url] = page
    return page
# Pythonic
import urllib.request as urllib	# Python 2.x: import urllib
import functools
def cache(func):
    saved = {}
    @functools.wraps(func)	# 以原函数为参数,保留原函数的各种信息
    def wrapper(url):
        if url in saved:
            return saved[url]
        else:
            page = func[url]
            saved[url] = page
            return page
    return wrapper
@cache
def web_lookup(url):
    return urllib.urlopen(url).read()
# 为已有函数增加 log 监控
def decorator_fun(fun):
    @functools.wraps(fun)
    def wrapper(*args, **kw):
        print('Current fun: ', fun.__name__)
        print('Position arguments: ', args)
        print('Key arguments: ', **kw)
        result = fun(*args, **kw)
        print(result)
    return wrapper
@decorator_fun
def add(a, b):
    return a + b
add(2, 3)
# 在原本的装饰器的外层又嵌套一个函数,就可以编写参数的装饰器
def read_file(filename='results.txt'):
    def decorator_fun(func):
        def new_fun(*args, **kw):
            result = func(*args, **kw)
            with open(filename, 'a') as f:
                f.write(result + '\n')
            return result
        return  new_fun
    return decorator_fun
@read_file(filename='log.txt')
def add(a, b):
    return a + b


# 编写类的 __call__ 方法,使类能够像函数一样的调用
from functools import wraps
class logResult(object):
    def __init__(self, filename='results.txt'):
        self.filename = filename
    
    def __call__(self, func):
        @wraps(func)
        def new_func(*args, **kw):
            result = func(*args, **kw)
            with open(filename, 'a') as f:
                f.write(result + '\n')
            return result
        self.send_notification()
        return new_func
    
    def send_notification(self):
        pass
@logResult('log.txt')
def add(a, b):
    return a + b

上下文管理器

# 上下文管理器:在代码执行前,先进行准备工作,执行完成后,再做收尾工作
# 打开的资源记得要释放
with open('data.txt') as f:
    data = f.read()
# 通过自定义类的 __enter__ 和 __exit__ 方法,可以自定义一个上下文管理器
class ReadFile(object):
    def __init__(self, filename):
        self.file = open(filename, 'r')
    
    def __enter__(self):
        returnn self.file
    
    def __exit__(self, type, value, traceback):
        '''type, value, traceback 分别代表错误的类型、值、追踪栈'''
        self.file.close()
        return True	# 返回 True 代表不抛出错误

with ReadFile('test.txt') as file_read:
    for line in file_read.readlines():
        print(line)
# with 语句先暂存了 ReadFile 类的 __exit__ 方法
# 然后调用 __enter__ 方法,并将结果返回给 with 语句
# 读取完成后调用之前暂存的 __exit__ 方法,关闭了文件

如果对你有帮助,记得点赞哦:)

    原文作者:驭风者
    原文地址: https://zhuanlan.zhihu.com/p/25892022
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞