python / python/cpython

`str.translate` caching values causes incorrect result

未关闭
#144,463 10 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

docs pending
主要语言
Python
星标
77.2k
派生
35.9k
PR 合并指标
PR 指标待抓取

描述

Bug report

Bug description:

It seems that str.translate is caching values internally and this is causing unintended results.

When the translation table returns an ordinal or a string ordinal string, it caches the values returned by __getitem__ and will not call the function again. However if you are returning a 2-length string this doesn't occur (and in fact calls __getitem__ an additional time for some reason?).

I expect that the __getitem__ be executed for every character since the function documentation does not mention this caching value and more-so the function behaves inconsistently.

This is likely caused by #65317.

class counting_translate_ord(dict[int, int]):
    def __init__(self) -> None:
        super().__init__()
        self.missing_calls = 0

    def __getitem__(self, key: int) -> int:
        self.missing_calls += 1
        return ord(str(self.missing_calls % 10))


table = counting_translate_ord()

print(("----").translate(table))  # 1111
print(table.missing_calls) # 1
print(("!@#$").translate(table))  # 2345
print(table.missing_calls) # 5


class counting_translate_str(dict[int, str]):
    def __init__(self) -> None:
        super().__init__()
        self.missing_calls = 0

    def __getitem__(self, key: int) -> str:
        self.missing_calls += 1
        return str(self.missing_calls % 10)


table = counting_translate_str()

print(("----").translate(table))  # 1111
print(table.missing_calls) # 1
print(("!@#$").translate(table))  # 2345
print(table.missing_calls) # 5


class counting_translate_2str(dict[int, str]):
    def __init__(self) -> None:
        super().__init__()
        self.missing_calls = 0

    def __getitem__(self, key: int) -> str:
        self.missing_calls += 1
        return format(self.missing_calls, "02d")[:2]


table = counting_translate_2str()

print(("----").translate(table))  # 02030405
print(table.missing_calls) # 5
print(("!@#$").translate(table))  # 07080910
print(table.missing_calls) # 10
CPython versions tested on:

3.12

Operating systems tested on:

Linux

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

首先,使用提供的 Python 复现程序运行三个计数翻译表案例,并比较它们的 getitem 调用次数和结果。然后定位 CPython 中 str.translate 的入口点和测试;当行为与文档化的契约一致,并且有回归测试覆盖时,即视为完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
python
领域
backend
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
基本清楚
新手友好度
45/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。