關於Python,99%的人不知道

前言:

python在近幾年得到飛速發展,誕生了許多代碼庫。但是小編髮現有很多代碼都未能使用到 Python 3 提供的新功能。本文作者介紹了相關功能的介紹,包括字符串格式化處理、文件路徑處理、類型提示、內置 LRU 緩存等等,幫助大家更好地利用 Python 3 書寫代碼。

注:文中的代碼示例基於 Python 3.7 編寫,爲方便使用,在每個功能後面都列出了該功能所需的最低 Python 版本。

對任何一種編程語言來說,字符串處理是一項很重要的內容,字符串處理往往是很多程序的基礎部分。由於人工處理字符串非常繁瑣,我們更希望用一種結構化的方法來處理它們。在 Python 中,我們一般使用 format 來進行結構化字符串處理,如下所示:
user = "Jane Doe" action = "buy"
​​​​​​​log_message = 'User {} has logged in and did an action {}.'.format( user, action )
除了 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}.'
Pathlib (3.4+)
如果需要處理文件路徑,我們可以使用 Python 3 中的 pathlib 庫,使對文件路徑的操作更加便捷。如果你對 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

類型提示 (3.5+)
靜態類型與動態類型是軟件工程中的一個熱門話題,Python 3 提供了支持 type hinting(類型提示)的方法,下面提供了一個示例:
def sentence_has_animal(sentence: str) -> bool:
return "animal" in sentence
sentence_has_animal("Donald had a farm without animals")
​枚舉 (3.4+)
Python 3 中的 Enum 類支持枚舉功能,可以使我們的程序變得更加簡潔。 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)
內置的 LRU 緩存 (3.2+)
Python 3 通過 lru_cache 來使用 LRU (Least Recently Used) 緩存。
下面的代碼定義了一個斐波拉契函數,由於該函數的運算需要多次遞歸,每次遞歸都會執行相同的工作,因此使用緩存能夠加速它的計算。
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
擴展的可迭代解析功能(3.0+)
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

數據類(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 object at 0x7fc4800e2cf8>
接來下我們使用數據類來實現上面的代碼:
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.
​​print(armor)# Armor(armor=5.2, description='Common armor.', level=2
隱式命名空間包(3.3+)
構建Python代碼有很多方法,其中一種就是在包(packages)中進行構建(即包含一個 __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 中,上面的每個文件夾都必須有一個 __init__.py 文件,該文件用於將其所在文件夾轉化爲 Python 包。然而在 Python 3 中,通過使用隱式命名空間包(Implicit Namespace Package:https://www.python.org/dev/peps/pep-0420/),這些文件就不再需要了。
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 包變成一個本地的命名空間包,這將會產生一些額外的限制,具體可以參考這篇文檔。
文中的代碼鏈接:
https://github.com/Weenkus/DataWhatNow-Codes/blob/master/things_you_are_probably_not_using_in_python_3_but_should/python%203%20examples.ipynb

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章