歡迎光臨
每天分享高質量文章

Python 2.7終結於7個月後,這是你需要瞭解的3.X炫酷新特性

(點擊上方快速關註並設置為星標,一起學Python)

來源:機器之心   作者:Vinko Kodžoman  

參與:Geek AI、思源    鏈接:

https://mp.weixin.qq.com/s/5Qxgm3dUEHU_BnVjU8Uchw

從 3.0 到 3.8,Python 3 已經更新了一波又一波,但似乎我們用起來和 2.7 沒有太大區別?以前該怎麼寫 2.7 的代碼現在就怎麼寫,只不過少數表達方式變了而已。在這篇文章中,作者介紹了 3.0 以來真正 Amazing 的新函式與新方法,也許這些方法我們都不太熟,但它們確實在實踐中非常重要。

許多人在瞭解到 Python 2.7 即將停止維護後,都開始將他們的 Python 版本從 2 切換到 3。截止到 5 月 19 號上午 10 點,Python 2.7 將終結於…

在這一段時間中,很多優秀開源專案與庫已經停止了對 2.7 的支持。例如到今年 1 月份,NumPy 將停止支持 Python 2;到今年年末,Ipython、Cython 和 Pandas 等等都將陸續停止支持 Python 2。

雖然我們都往 3.X 遷移,但許多人編寫的 Python 3 代碼仍然看起來像 Python 2 一樣,只不過加入了一些括號或改了些 API。在本文中,作者將展示一些令人激動的 Python 3.X 新特性。這些特性或方法都是 Python 3 各個版本中新加的,它們相比傳統的 Python 方法,更容易解決實踐中的一些問題。

所有的示例都是在 Python 3.7 的環境下編寫的,每個特性示例都給出了其正常工作所需的最低的 Python 版本。

格式化字串 f-string(最低 Python 版本為 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-string」進行字串插入的靈活方法。使用「f-string」編寫的與上面功能相同的代碼是這樣的:

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.

相比於常見的字串格式符 %s 或 format 方法,f-strings 直接在占位符中插入變數顯得更加方便,也更好理解。

路徑管理庫 Pathlib(最低 Python 版本為 3.4)

f-string 非常強大,但是有些像檔案路徑這樣的字串有他們自己的庫,這些庫使得對它們的操作更加容易。Python 3 提供了一種處理檔案路徑的抽象庫「pathlib」。如果你不知道為什麼應該使用 pathlib,請參閱下麵這篇 Trey Hunner 編寫的炒雞棒的博文:「https://treyhunner.com/2018/12/why-you-should-be-using-pathlib/」

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(最低 Python 版本為 3.5)

靜態和動態型別是軟體工程中一個熱門的話題,幾乎每個人 對此有自己的看法。讀者應該自己決定何時應該編寫何種型別,因此你至少需要知道 Python 3 是支持型別提示的。

def sentence_has_animal(sentence: str) -> bool:
  return "animal" in sentence

sentence_has_animal("Donald had a farm without animals")
# True

列舉(最低 Python 版本為 3.4)

Python 3 支持通過「Enum」類編寫列舉的簡單方法。列舉是一種封裝常量串列的便捷方法,因此這些串列不會在結構性不強的情況下隨機分佈在代碼中。

from enum import Enum, auto

class Monster(Enum):
    ZOMBIE = auto()
    WARRIOR = auto()
    BEAR = auto()

print(Monster.ZOMBIE)
# Monster.ZOMBIE

列舉是符號名稱(成員)的集合,這些符號名稱與唯一的常量值系結在一起。在列舉中,可以通過標識對成員進行比較操作,列舉本身也可以被遍歷。

參考:https://docs.python.org/3/library/enum.html

for monster in Monster:
    print(monster)

# Monster.ZOMBIE
# Monster.WARRIOR
# Monster.BEAR

原生 LRU 快取(最低 Python 版本為 3.2)

目前,幾乎所有層面上的軟體和硬體中都需要快取。Python 3 將 LRU(最近最少使用演算法)快取作為一個名為「lru_cache」的裝飾器,使得對快取的使用非常簡單。

下麵是一個簡單的斐波那契函式,我們知道使用快取將有助於該函式的計算,因為它會通過遞迴多次執行相同的工作。

import time

def fib(number: int) -> int:
    if number == 0return 0
    if number == 1return 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 == 0return 0
    if number == 1return 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

擴展的可迭代物件解包(最低 Python 版本為 3.0)

對於這個特性,代碼就說明瞭一切。

參考:https://www.python.org/dev/peps/pep-3132/

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 class 裝飾器(最低 Python 版本為 3.7)

Python 3 引入了「data class」,它們沒有太多的限制,可以用來減少對樣板代碼的使用,因為裝飾器會自動生成諸如「__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/>

使用「Data class」實現相同的 Armor 類。

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)

隱式命名空間包(最低 Python 版本為 3.3)

一種組織 Python 代碼檔案的方式是將它們封裝在程式包中(包含一個「__init__.py」的檔案夾)。下麵是官方文件提供的示例。

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 中,上面每個檔案夾都必須包含將檔案夾轉化為 Python 程式包的「__init__.py」檔案。在 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」,把它從一個檔案夾中刪除會將該檔案夾變成一個本地命名空間包,這會帶來一些額外的限制。本地命名空間包的官方文件給出了一個很好的示例,並且明確指出了所有的限制。

結語

和網上幾乎所有的技術串列一樣,本文給出的串列也並不完整。希望這篇文章至少向你展示了一些以前不知道的 Python 3 功能,它將幫助你編寫出更加乾凈、 直觀的代碼。

最後,本文中給出的所有代碼都可以在作者的 GitHub 上找到:https://github.com/Weenkus/DataWhatNow-Codes/blob/master/things_you_are_probably_not_using_in_python_3_but_should/python%203%20examples.ipynb

原文鏈接:https://datawhatnow.com/things-you-are-probably-not-using-in-python-3-but-should/

赞(0)

分享創造快樂