python / python/cpython

`str.translate` caching values causes incorrect result

Offen
#144,463 10 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

docs pending
Vorherrschende Sprache
Python
Sterne
77.2k
Forks
35.9k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

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

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Führen Sie zunächst den bereitgestellten Python-Reproducer für die drei Fälle mit zählenden Übersetzungstabellen aus und vergleichen Sie die Anzahl ihrer getitem-Aufrufe sowie ihre Ergebnisse. Suchen Sie anschließend den CPython-Einstiegspunkt und die Tests für str.translate; abgeschlossen ist die Aufgabe, wenn das Verhalten mit dem dokumentierten Vertrag übereinstimmt und durch Regressionstests abgedeckt ist.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
backend
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
45/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.