python 3 好在哪里?【译】

阿里云-轻量应用服务器

原文链接:Things you’re probably not using in Python 3 – but should – Data, what now? turns

格式化字符串 f-strings (3.6+)

将变量组合成符串输出,是任何一门语言都要碰到的问题,python 2以前是这么处理的:

user = "Jane Doe"
action = "buy"
log_message = 'User {} has logged in and did an action {}.'.format(
  user,
  action
)
print(log_message)
# User Jane Doe has logged in and did an action buy.

与python 2的format 方法不同,python 3提供了f-strings的方法:

user = "Jane Doe"
action = "buy"
log_message = f'User {user} has logged in and did an action {action}.'
print(log_message)
# User Jane Doe has logged in and did an action buy.

真香!

Pathlib (3.4+)

python 3 提供的 Pathlib 文件路径包比os.path() 好用多了,如果你不太了解这个类库,请查看:Why you should be using pathlib – Trey Hunner

from pathlib import Path
root = Path('post_sub_folder')
print(root)
# post_sub_folder
path = root / 'happy_user'
# Make the path absolute
print(path.resolve())
# /home/weenkus/Workspace/Projects/DataWhatNow-Codes/how_your_python3_should_look_like/post_sub_folder/happy_user

类型提示 Type hinting (3.5+)

众所周知,Python 是动态类型语言,运行时不需要指定变量类型。Python的主要卖点之一就是它是动态类型的,这一点也不会改变。而在2014年9月,Guido van Rossum (Python BDFL) 创建了一个Python增强提议(PEP-484),为Python添加类型提示(Type Hints),写不写你自己看着办喽:

# 变量注解
a: int = 5
b: bool = True
f: float = 5.0
s: str = "abc"

# 函数注解
def sentence_has_animal(sentence: str) -> bool:
  return "animal" in sentence
sentence_has_animal("Donald had a farm without animals")
# True

内置枚举类型 Enumerations (3.4+)

Python 3 可以通过 Enum 类型非常方便的创建枚举类型:

from enum import Enum, auto
class Monster(Enum):
    ZOMBIE = auto()
    WARRIOR = auto()
    BEAR = auto()
    
print(Monster.ZOMBIE)
# Monster.ZOMBIE
for monster in Monster:
    print(monster)
# Monster.ZOMBIE
# Monster.WARRIOR
# Monster.BEAR

Built-in LRU cache (3.2+)

LRU (Least Recently Used) 是缓存置换策略中的一种常用的算法。当缓存队列已满时,新的元素加入队列时,需要从现有队列中移除一个元素,LRU 策略就是将最近最少被访问的元素移除,从而腾出空间给新的元素。

下面是一个斐波纳契函数的实现,将让你看到缓存机制带来的好处:

import time
def fib(number: int) -> int:
    if number == 0: return 0
    if number == 1: return 1
    
    return fib(number-1) + fib(number-2)
start = time.time()
fib(40)
print(f'Duration: {time.time() - start}s')
# Duration: 30.684099674224854s

现在我们用lru_cache缓存机制来优化以上代码:

from functools import lru_cache
@lru_cache(maxsize=512)
def fib_memoization(number: int) -> int:
    if number == 0: return 0
    if number == 1: return 1
    
    return fib_memoization(number-1) + fib_memoization(number-2)
start = time.time()
fib_memoization(40)
print(f'Duration: {time.time() - start}s')
# Duration: 6.866455078125e-05s

 

数量可变的位置参数 Extended iterable unpacking (3.0+)

官方文档:PEP 3132 — Extended Iterable Unpacking | Python.org

head, *body, tail = range(5)
print(head, body, tail)
# 0 [1, 2, 3] 4
py, filename, *cmds = "python3.7 script.py -n 5 -l 15".split()
print(py)
print(filename)
print(cmds)
# python3.7
# script.py
# ['-n', '5', '-l', '15']
first, _, third, *_ = range(10)
print(first, third)
# 0 2

数据类 Data classes (3.7+)

Python 3 引入了数据类型类,这样你在新建数据模型时不用写__init__() and __repr()__等方法。如果,python 2:

class Armor:
    
    def __init__(self, armor: float, description: str, level: int = 1):
        self.armor = armor
        self.level = level
        self.description = description
                 
    def power(self) -> float:
        return self.armor * self.level
    
armor = Armor(5.2, "Common armor.", 2)
armor.power()
# 10.4
print(armor)
# <__main__.Armor object at 0x7fc4800e2cf8>

 

而在python 3 中

from dataclasses import dataclass
@dataclass
class Armor:
    armor: float
    description: str
    level: int = 1
    
    def power(self) -> float:
        return self.armor * self.level
    
armor = Armor(5.2, "Common armor.", 2)
armor.power()
# 10.4
print(armor)
# Armor(armor=5.2, description='Common armor.', level=2)

隐式命名空间包Implicit namespace packages (3.3+)

以前创建名称空间包时,python 2 是这样的:

sound/                          Top-level package
      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

以上每个文件夹里都会有一个 __init__.py 的文件,这个文件会让这个文件夹被python 识别为packages。而python 3.3 引入了PEP 420 — Implicit Namespace Packages | Python.org  ,不再需要这个文件。

sound/                          Top-level package
      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for filters
              equalizer.py
              vocoder.py
              karaoke.py
              ...