回顧一下 Python 3.4 中的枚舉
Python 3.4 在 2014 年首次發(fā)布,盡管它已經(jīng)發(fā)布了很長(zhǎng)時(shí)間,但它引入的許多特性都沒(méi)有被充分利用,而且相當(dāng)酷。下面是其中的三個(gè)。
枚舉
我最喜歡的邏輯謎題之一是自我描述的 史上最難的邏輯謎題。在其中,它談到了三個(gè)“神”,他們被稱為 A、B 和 C,他們的身份是真、假和隨機(jī),按一定順序排列。你可以問(wèn)他們問(wèn)題,但他們只用神的語(yǔ)言回答,其中 “da” 和 “ja” 表示 “是” 和 “不是”,但你不知道哪個(gè)是哪個(gè)。
如果你決定使用 Python 來(lái)解決這個(gè)問(wèn)題,你將如何表示神的名字和身份以及神的語(yǔ)言中的詞語(yǔ)?傳統(tǒng)的答案是使用字符串。然而,字符串的拼寫(xiě)錯(cuò)誤可能會(huì)帶來(lái)災(zāi)難性的后果。
如果在解題的關(guān)鍵部分,你用字符串 “jaa” 而不是 “ja” 進(jìn)行比較,你就會(huì)得到一個(gè)錯(cuò)誤的答案。雖然謎題沒(méi)有說(shuō)明風(fēng)險(xiǎn)是什么,但這可能是最好的避免方式。
enum 模塊讓你能夠以一種可調(diào)試但安全的方式來(lái)定義這些東西:
- 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()
枚舉的一個(gè)好處是,在調(diào)試日志或異常中,枚舉的呈現(xiàn)方式是有幫助的:
- 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
在開(kāi)發(fā)游戲的“基礎(chǔ)設(shè)施”層時(shí),你想通用地處理各種游戲?qū)ο螅匀辉试S這些對(duì)象自定義動(dòng)作。為了使這個(gè)例子更容易解釋,假設(shè)這是一個(gè)基于文本的游戲。當(dāng)你使用一個(gè)對(duì)象時(shí),大多數(shù)情況下,它只會(huì)打印 You are using <x>
當(dāng)你獲得一個(gè)物品時(shí),它通常會(huì)被添加到庫(kù)存中。然而,一塊特別重的石頭會(huì)砸碎一個(gè)隨機(jī)物品。如果發(fā)生這種情況,庫(kù)存中會(huì)失去該物體。
處理這個(gè)問(wèn)題的一個(gè)方法是在物品上設(shè)置 use 和 acquire 方法。隨著游戲復(fù)雜性的增加,這些方法會(huì)越來(lái)越多,使游戲?qū)ο笞兊秒y以編寫(xiě)。
相反,functools.singledispatch 允許你以安全和尊重命名空間的方式追溯性地添加方法。
你可以定義沒(méi)有行為的類:
- 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)
對(duì)于火炬來(lái)說(shuō),這些通用的實(shí)現(xiàn)已經(jīng)足夠了:
- import functools
- @functools.singledispatch
- def use(x):
- print("You use", x.name)
- @functools.singledispatch
- def acquire(x, inventory):
- inventory.add(x)
- You use torch
- You have ['torch']
然而,劍和石頭需要一些專門(mén)的功能:
- 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 ['sword', 'torch']
- 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 ['sword', 'rock']
巖石可能壓碎了火炬,但你的代碼更容易閱讀。
pathlib
從一開(kāi)始,Python 中文件路徑的接口就是“智能字符串操作”?,F(xiàn)在,通過(guò) pathlib,Python 有了一種面向?qū)ο蟮姆椒▉?lái)操作路徑。
- import pathlib
- gitconfig = pathlib.Path.home() / ".gitconfig"
- text = gitconfig.read_text().splitlines()
誠(chéng)然,用 / 作為操作符來(lái)生成路徑名有點(diǎn)俗氣,但在實(shí)踐中卻不錯(cuò)。像 .read_text() 這樣的方法允許你從小文件中獲取文本,而不需要手動(dòng)打開(kāi)和關(guān)閉文件句柄。
這使你可以集中精力處理重要的事情:
- for line in text:
- if not line.strip().startswith("name"):
- continue
- print(line.split("=")[1])
- Moshe Zadka
歡迎來(lái)到 2014 年
Python 3.4 大約在七年前就發(fā)布了,但是在這個(gè)版本中首次出現(xiàn)的一些功能非???,而且沒(méi)有得到充分利用。如果你還沒(méi)使用,那么將他們添加到你的工具箱中。