Skip to content

str.translate caching values causes incorrect result #144463

@ktbarrett

Description

@ktbarrett

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions