DedSec Project

UnboundLocalError — DedSec Project

Python UnboundLocalError: ανάγνωση local πριν την ανάθεση Αναπαραγωγή Η Python αποφασίζει κατά τη μεταγλώττιση ότι το counter είναι local στη broken, επειδή υπάρχει ανάθεση μέσα της. Η…

Python UnboundLocalError: ανάγνωση local πριν την ανάθεση

Αναπαραγωγή

counter = 10
def broken():
    print(counter)
    counter = counter + 1

broken()

Η Python αποφασίζει κατά τη μεταγλώττιση ότι το counter είναι local στη broken, επειδή υπάρχει ανάθεση μέσα της. Η προηγούμενη ανάγνωση προκαλεί UnboundLocalError, παρότι υπάρχει global counter. Είναι υποκατηγορία του NameError, αλλά εδώ γνωρίζουμε ότι το όνομα είναι local και δεν έχει αρχικοποιηθεί.

Προτίμησε ρητή κατάσταση

def increment(counter):
    return counter + 1

assert increment(10) == 11
assert increment(0) == 1

Η συνάρτηση δεν αλλάζει globals και ελέγχεται εύκολα. Σε closure όπου θέλεις σκόπιμα να αλλάζεις μεταβλητή του εξωτερικού scope, το nonlocal μπορεί να είναι σωστό. Το global αλλάζει binding του module και δεν πρέπει να μπαίνει μόνο για να εξαφανιστεί το μήνυμα.

Έλεγχος διακλαδώσεων

def label(flag):
    if flag:
        result = "ready"
    return result

Η label(False) αποτυγχάνει, επειδή δεν εκτελέστηκε η ανάθεση. Αρχικοποίησε πριν από το if, επέστρεψε τιμή σε κάθε διαδρομή ή χειρίσου ρητά την άγνωστη περίπτωση. Έλεγξε επίσης try/except: μια ανάθεση μέσα στο try μπορεί να παραλειφθεί. Ακόμη και το += θεωρείται ανάγνωση και εγγραφή της local μεταβλητής.

Εργαστήριο

Δοκίμασε label(True) και label(False), μετά διόρθωσε και τις δύο διαδρομές. Φτιάξε closure με nonlocal και σύγκρινέ το με την increment. Τεκμηρίωσε αν η κατάσταση πρέπει να επιστρέφεται, να μοιράζεται σε closure ή να αποθηκεύεται σε αντικείμενο. Έλεγξε κάθε branch με test.

Υποχρεωτικό αποτέλεσμα για κάθε διαδρομή

Μια local μεταβλητή πρέπει να έχει τιμή πριν διαβαστεί σε κάθε branch. Σε δικό σου προσωρινό παράδειγμα ανάθεσε result μόνο όταν flag=True και δοκίμασε και False. Διόρθωσε με δύο ανεξάρτητες επιστροφές, μετά με σαφές default και τέλος με raise ValueError για μη υποστηριζόμενη είσοδο. Οι τρεις λύσεις δεν σημαίνουν το ίδιο: το default μπορεί να κρύβει υποχρεωτική έλλειψη, ενώ το exception δηλώνει καθαρά ότι δεν υπάρχει έγκυρο αποτέλεσμα.