高效 Python (Effective Python)

有效的 Python

Effective Python

Python 思维方式

第1条 知道你使用的 Python 版本
python --version
# Python 3.8.10

Python 3 通常是 python3

python3 --version
#  Python 3.8.10

在运行中,可以通过 sys.version 来获取 python 的版本

>>> import sys
>>> print(sys.version_info)
sys.version_info(major=3, minor=8, micro=10, releaselevel='final', serial=0)
>>> print(sys.version)
3.8.10 (tags/v3.8.10:3d8993a, May  3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)]
第2条 遵循 PEP 8 编程风格
第3条 知道 bytes 和 str 的区别

bytes 实例包含的是原始数据,即8位无符号值
str 包含的是 Unicode 码点
如果需要从文件中读写二进制数据,那么需要用二进制的模式打开文件 “wb” 或 “rb”
如果需要从文件中读写文本数据,需要注意操作系统默认的编码影响,可以指定 encoding 编码来避免影响。

第4条 用 f-string 取代 C 风格的格式化或者 str.format 方法

三种方式对别如下

key = 'my_var'
f_string = f'{
     key:<10} = {
     value:.2f}'
str_args = '{:<10} = {:.2f}'.format(key, value)
str_kw = '{key:<10} = {value:.2f}'.format(key=key, value=value)
c_tuple = '%-10s = %.2f' % (key, value)
c_dict = '%(key)-10s = %(value).2f' % {
   'key': key, 'value': value}
assert c_tuple == c_dict == f_string
assert str_args == str_kw == f_string
第5条 用辅助函数取代复杂表达式
  • Python 的语法灵活导致可以写复杂且难以阅读的单行表达式
  • 当重复用到同一逻辑时,可以把逻辑移到辅助函数中
  • if else 表达式比 or/and 布尔运算更易读
from urllib.parse import parse_qs


def test_complex_expressions():
    my_values = parse_qs('red=5&blue=0&green=', keep_blank_values=True)
    red = int(my_values.get('red', [''])[0] or 0)
    blue = int(my_values.get('blue', [''])[0] or 0)
    green = int(my_values.get('green', [''])[0] or 0)
    assert red == 5 and blue == 0 and green == 0


def test_if_else():
    my_values = parse_qs('red=5&blue=0&green=', keep_blank_values=True)
    red_str = my_values.get('red', [''])
    red = int(red_str[0]) if red_str[0] else 0
    blue_str = my_values.get('blue', [''])
    blue = int(blue_str[0]) if blue_str[0] else 0
    green_str = my_values.get('green', [''])
    green = int(green_str[0]) if green_str[0] else 0
    assert red == 5 and blue == 0 and green == 0


def get_first_int(values, key, default=0):
    found = values.get(key, [''])
    if found[0]:
        return int(found[0])
    return default


def test_helper_function():
    my_values = parse_qs('red=5&blue=0&green=', keep_blank_values=True)
    red = get_first_int(my_values, "red", 0)
    blue = get_first_int(my_values, "blue", 0)
    green = get_first_int(my_values, "green", 0)
    assert red == 5 and blue == 0 and green == 0
第6条 把数据结构直接拆分到多个变量里
snacks = [('bacon', 350), ('donut', 240), ('muffin', 190)]
for i in range(len(snacks)):
    item = snacks[i]
    name = item[0]
    calories = item[1]
    print(f'#{
     i+1}: {
     name} has {
     calories} calories')

# 使用 enumerate 加上解包赋值方式简化代码
for rank, (name, calories) in enumerate(snacks, 1):
    print(f'#{
     rank}: {
     name} has {
     calories} calories')
第7条 用 enumerate 取代 range
flavor_list = ['vanilla', 'chocolate', 'pecan', 'strawberry']
for i in range(len(flavor_list)):
    flavor = flavor_list[i]
    print(f'{
     i + 1}: {
     flavor}')

# 使用 enumerate 比 range 代码更简洁
for i, flavor in enumerate(flavor_list):
 print(f'{
     i + 1}: {
     flavor}')
第8条 用 zip 同时遍历多个迭代器

zip 可以同时遍历多个迭代器,zip 只迭代到最短的迭代器结束,如果需要迭代到最长的迭代器结束,可以使用 itertools.zip_longest

names = ['Cecilia', 'Lise', 'Marie']
counts = [len(n) for n in names]

longest_name = None
max_count = 0

for i, name in enumerate(names):
    count = counts[i]
    if count > max_count:
        longest_name = name
        max_count = count

# 使用 zip 同时遍历多个迭代器
for name, count in zip(names, counts):
    if count > max_count:
        longest_name = name
        max_count = count

# 遍历最长的迭代器
import itertools
for name, count in itertools.zip_longest(names, counts):
    print(f'{
     name}: {
     count}')
第9条 避免在 for 或 while 循环后使用 else

else 块只在循环没有被 break 时才会执行,容易引起混乱,尽量避免使用

第10条 用赋值表达式减少重复代码
count = fresh_fruit.get('lemon', 0)
if count:
    make_lemonade(count)
else:
    out_of_stock()

# 使用赋值表达式 := 简化为
if count := fresh_fruit.get('lemon', 0):
    make_lemonade(count)
else:
    out_of_stock()
count = fresh_fruit.get('banana', 0)
if count >= 2:
    pieces = slice_bananas(count)
    to_enjoy = make_smoothies(pieces)
else:
    count = fresh_fruit.get('apple', 0)
    if count >= 4:
        to_enjoy = make_cider(count)
    else:
        count = fresh_fruit.get('lemon', 0)
        if count:
            to_enjoy = make_lemonade(count)
        else:
            to_enjoy‘= 'Nothing'

# 使用赋值表达式 := 来减少缩进
if (count := fresh_fruit.get('banana', 0)) >= 2:
    pieces = slice_bananas(count)
    to_enjoy = make_smoothies(pieces)
elif (count := fresh_fruit.get('apple', 0)) >= 4:
    to_enjoy = make_cider(count)
elif count := fresh_fruit.get('lemon', 0):
    to_enjoy = make_lemonade(count)
else:
    to_enjoy = 'Nothing'

列表与字典

第11条 学会对序列做切片
a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
print('Middle two: ', a[3:5])
print('All but ends:', a[1:7])

# 从开头开始切片不需要写 0
assert a[:5] == a[0:5]

# 切片到结尾时,不要写结束索引
assert a[5:] == a[5:len(a)]

# 当需要相对于尾巴进行切片时,使用负数索引
a[:-1]

# 当索引超出范围时,切片会忽略缺失值
first_twenty_items = a[:20]
last_twenty_items = a[-20:]

# list 的切片返回的是新的 list 对象,对切片的修改不会影响原来的 list
b = a[3:]
print('Before: ', b)
# ['d', 'e', 'f', 'g', 'h']
b[1] = 99
print('After: ', b)
# ['d', 99, 'f', 'g', 'h']
print('No change:', a)
# ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

# 对切片范围的赋值,会使原来的 list 收缩或变长
print('Before ', a)
# ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
a[2:7] = [99, 22, 14]
print('After ', a)
# ['a', 'b', 99, 22, 14, 'h']
a[2:3] = [47, 11]
print('After ', a
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值