回顾 Python 3.4 为 enum 所做的工作

此外,探索一些未被充分利用但仍然有用的 Python 功能。
51 位读者喜欢这篇文章。

这是关于 Python 3.x 版本中首次出现的功能系列文章的第五篇。Python 3.4 于 2014 年首次发布,尽管它已经发布很长时间了,但它引入的许多功能都未被充分利用,而且非常酷。以下是其中三个。

enum

我最喜欢的逻辑谜题之一是自描述的史上最难逻辑谜题。 其中,它谈到了三个被称为 A、B 和 C 的神。 他们的身份是 True、False 和 Random,顺序不定。 你可以问他们问题,但他们只用神语回答,其中“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 ['torch']

但是,剑和石头需要一些专门的功能

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

自时间开始以来,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 大约在七年前发布,但此版本中首次出现的一些功能很酷且未被充分利用。 如果您还没有这样做,请将它们添加到您的工具包中。

接下来阅读什么
标签
Moshe sitting down, head slightly to the side. His t-shirt has Guardians of the Galaxy silhoutes against a background of sound visualization bars.
自 1998 年以来,Moshe 一直参与 Linux 社区,帮助举办 Linux “安装派对”。 他自 1999 年以来一直编写 Python 程序,并为核心 Python 解释器做出了贡献。 Moshe 在 DevOps/SRE 这些术语出现之前就已经从事相关工作,他非常关心软件可靠性、构建可重复性以及其他此类事情。

评论已关闭。

© . All rights reserved.