python / python/mypy

Type narrowing for Optional[T] fails inside an else branch inside a while cycle

Offen
#11,947 0 Kommentare 1 Reaktion 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

bug topic-type-narrowing
Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

Bug Report

from typing import Optional                                                      
                                                                                 
                                                                                 
class Node:                                                                      
    def __init__(self, value: int):                                      
        self.value = value                                                       
        self.next: Optional[Node] = None                                         
                                                                                 
                                                                                 
def foo(node: Node) -> None:                                                     
    while node.next is not None:                                                 
        if node.value != node.next.value:                                        
            node = node.next                                                     
        else:                                                                    
            node.next = node.next.next   # <-- HERE

Expected Behavior

No mypy errors. Mypy should know that node.next is not None in the else branch.

Actual Behavior

Mypy says error: Item "None" of "Optional[Node]" has no attribute "next" on the line marked by <-- HERE. (With column numbers turned on, the location is the beginning of node.next.next.)

Interestingly, everything is OK if the branches of if are reversed:

def foo(node: Node) -> None:                                                     
    while node.next is not None:                                                 
        if node.value == node.next.value:                                        
            node.next = node.next.next                                           
        else:                                                                    
            node = node.next                                                     

Writing assert node is not None before the problematic line also fixes the error (but seems quite redundant).

Your Environment

  • Mypy version used: mypy 0.930
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): default, no config files
  • Python version used: Python 3.10.1
  • Operating system and version: Arch 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

Beginne damit, mypy 0.930 ohne Konfiguration für das im Issue enthaltene Optional[Node]-Beispiel auszuführen; vergleiche dann die beiden Verzweigungsreihenfolgen und die assert-Variante. Verfolge die Typverengung rund um die while-Bedingung und die Zuweisung; abgeschlossen ist die Aufgabe, wenn das ursprüngliche Beispiel ohne das redundante assert keinen Fehler meldet.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

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

Neue Issues direkt in Ihr Postfach

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