翻译自: https://datawhatnow.com/things-you-are-probably-not-using-in-python-3-but-should/
由于python 2 的停止支持(Python EOL), 许多人开始将他们的Python版本从2切换到3. 但是我发现很多 Python 3 代码仍然像 Python 2. 下面,我展示了一些你只能在 Python 3 中使用的激动人心的特性例子, 希望它能让你用 Python 解决问题变得更容易.
所有的例子都在 Python 3.7 下测试通过, 并且每个特性都在括号里列出了拥有这个特性的最小 Python 版本
f-字符串(f-strings) (3.6+)
在任何编程语言中没有字符串是很难做任何事情的. 为了保持清晰, 你希望有一个结构化的方式来处理字符串. 大多数使用python 的人推荐使用 format
方法
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.
与 format
相似, Python 3 提供了一个通过 f-strings
进行字符串插值的灵活方法, 上面的代码使用 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+)
f-strings 让人惊奇, 但是一些像文件路径这样的字符串有自己的库,这使得它们的操作更加容易. Python 3 提供了 pathlib 模块来处理文件路径. 如果你不确定为什么应该使用 pathlib, 试着读一下这篇精彩的帖子: Why you should be using pathlib – by 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 3 支持的 “类型提示” (type hints)
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
An enumeration is a set of symbolic names (members) bound to unique, constant values. Within an enumeration, the members can be compared by identity, and the enumeration itself can be iterated over.
for monster in Monster:
print(monster)
# Monster.ZOMBIE
# Monster.WARRIOR
# Monster.BEAR
内建的LRU缓存(Built-in LRU cache) (3.2+)
缓存几乎存在于我们今天使用的软件和硬件的任何水平切片中。Python 3通过暴露一个名为lru_cache
的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
来优化它(这种优化方法被称为 memoization ) 执行时间将从秒降到毫秒
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+)
功能描述在这 (docs).
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']
数据类(Data classes) (3.7+)
Python 3引入了没有很多限制的数据类, 可以用来减少样板代码, 因为decorator会自动生成特殊的方法, 例如__init__()
和__repr()__
. 根据官方提议, 它们被描述为“具有默认值的可变命名元组”.
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>
Armour使用 数据类 的相同实现:
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+)
“包” (拥有 __init__.py
文件的目录) 是结构化 Python 代码的一种方法. 下面的例子来自 Python 官方文档
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
...
在 Python 2 中, 上面的每个文件夹都必须有__init__
来将普通文件夹转换成Python包. 在 Python 3 中, 随着隐式命名空间包的引入, 这些文件不再需要.
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
...
校订: 像很多人说的, 通过官方文档 PEP 420 Specification, 这个功能并不像我这段指出的那么简单. __init__.py
对于常规包仍然是必需的, 将其从文件夹结构中删除会将其转换为带有附加限制的原生命名空间包. 官方示例 official docs on native namespace packages 提供了一个例子
结束语
像互联网上几乎所有的列表一样,这个列表并不完整。我希望这篇文章已经向您展示了至少一个您以前不知道的Python 3功能,并且它将帮助您编写更干净、更直观的代码。像往常一样,所有的代码都可以在GitHub上找到。