Linux中國

回顧一下 Python 3.4 中的枚舉

這是 Python 3.x 首發特性系列文章的第五篇。Python 3.4 在 2014 年首次發布,儘管它已經發布了很長時間,但它引入的許多特性都沒有被充分利用,而且相當酷。下面是其中的三個。

枚舉

我最喜歡的邏輯謎題之一是自我描述的 史上最難的邏輯謎題。在其中,它談到了三個「神」,他們被稱為 A、B 和 C,他們的身份是真、假和隨機,按一定順序排列。你可以問他們問題,但他們只用神的語言回答,其中 「da」 和 「ja」 表示 「是」 和 「不是」,但你不知道哪個是哪個。

如果你決定使用 Python 來解決這個問題,你將如何表示神的名字和身份以及神的語言中的詞語?傳統的答案是使用字元串。然而,字元串的拼寫錯誤可能會帶來災難性的後果。

如果在解題的關鍵部分,你用字元串 「jaa」 而不是 「ja」 進行比較,你就會得到一個錯誤的答案。雖然謎題沒有說明風險是什麼,但這可能是最好的避免方式。

enum 模塊讓你能夠以一種可調試但安全的方式來定義這些東西:

import enum

@enum.unique
class Name(enum.Enum):
    A = enum.auto()
    B = enum.auto()
    C = enum.auto()

@enum.unique
class Identity(enum.Enum):
    RANDOM = enum.auto()
    TRUE = enum.auto()
    FALSE = enum.auto()

@enum.unique
class Language(enum.Enum):
    ja = enum.auto()
    da = enum.auto()

枚舉的一個好處是,在調試日誌或異常中,枚舉的呈現方式是有幫助的:

name = Name.A
identity = Identity.RANDOM
answer = Language.da
print("I suspect", name, "is", identity, "because they answered", answer)
    I suspect Name.A is Identity.RANDOM because they answered Language.da

functools.singledispatch

在開發遊戲的「基礎設施」層時,你想通用地處理各種遊戲對象,但仍然允許這些對象自定義動作。為了使這個例子更容易解釋,假設這是一個基於文本的遊戲。當你使用一個對象時,大多數情況下,它只會列印 You are using <x>。但是使用一把特殊的劍可能需要隨機滾動,否則會失敗。

當你獲得一個物品時,它通常會被添加到庫存中。然而,一塊特別重的石頭會砸碎一個隨機物品。如果發生這種情況,庫存中會失去該物體。

處理這個問題的一個方法是在物品上設置 useacquire 方法。隨著遊戲複雜性的增加,這些方法會越來越多,使遊戲對象變得難以編寫。

相反,functools.singledispatch 允許你以安全和尊重命名空間的方式追溯性地添加方法。

你可以定義沒有行為的類:

class Torch:
    name="torch"

class Sword:
    name="sword"

class Rock:
    name="rock"
import functools

@functools.singledispatch
def use(x):
    print("You use", x.name)

@functools.singledispatch
def acquire(x, inventory):
    inventory.add(x)

對於火炬來說,這些通用的實現已經足夠了:

inventory = set()

def deploy(thing):
    acquire(thing, inventory)
    use(thing)
    print("You have", [item.name for item in inventory])

deploy(Torch())
    You use torch
    You have [&apos;torch&apos;]

然而,劍和石頭需要一些專門的功能:

import random

@use.register(Sword)
def use_sword(sword):
    print("You try to use", sword.name)
    if random.random() < 0.9:
        print("You succeed")
    else:
        print("You fail")

deploy(sword)
    You try to use sword
    You succeed
    You have [&apos;sword&apos;, &apos;torch&apos;]
import random

@acquire.register(Rock)
def acquire_rock(rock, inventory):
    to_remove = random.choice(list(inventory))
    inventory.remove(to_remove)
    inventory.add(rock)

deploy(Rock())
    You use rock
    You have [&apos;sword&apos;, &apos;rock&apos;]

岩石可能壓碎了火炬,但你的代碼更容易閱讀。

pathlib

從一開始,Python 中文件路徑的介面就是「智能字元串操作」。現在,通過 pathlib,Python 有了一種面向對象的方法來操作路徑。

import pathlib
gitconfig = pathlib.Path.home() / ".gitconfig"
text = gitconfig.read_text().splitlines()

誠然,用 / 作為操作符來生成路徑名有點俗氣,但在實踐中卻不錯。像 .read_text() 這樣的方法允許你從小文件中獲取文本,而不需要手動打開和關閉文件句柄。

這使你可以集中精力處理重要的事情:

for line in text:
    if not line.strip().startswith("name"):
        continue
    print(line.split("=")[1])
     Moshe Zadka

歡迎來到 2014 年

Python 3.4 大約在七年前就發布了,但是在這個版本中首次出現的一些功能非常酷,而且沒有得到充分利用。如果你還沒使用,那麼將他們添加到你的工具箱中。

via: https://opensource.com/article/21/5/python-34-features

作者:Moshe Zadka 選題:lujun9972 譯者:geekpi 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國