Domanda Risolto esercizio python

Stato
Discussione chiusa ad ulteriori risposte.

markito

Utente Iron
3 Marzo 2021
23
7
2
19
Ultima modifica:
Python:
import sys
import os

def is_triangle(a,b,c):
    if (a + b > c) and (a + c > b) and (b + c > a):
        print "Yes"
    else:
        print "No"

def prompt_user():
    prompt = "Please enter side "
    for value in ['a', 'b', 'c']:
        new_prompt = prompt + value +': ' # modify prompt for value in loop
        my_input = raw_input(new_prompt)   # get input
        float_input = float(my_input)      # convert the entered value to float
        exec ("%s=%f" % (value, float_input))
    a = int(a)
    b = int(b)
    c = int(c)
    is_triangle(a,b,c)

def main():
    # is_triangle(5,3,4)
    # is_triangle(5,3,12)
    prompt_user()

if __name__ == '__main__':
    main()


Salve a tutti, inizio questa discussione perché non riesco a risolvere l'errore seguente:

line 17, in prompt_user
a = int(a)
UnboundLocalError: local variable 'a' referenced before assignment

nonostante mi pare di aver già assegnato la variabile locale tramite il comando : " exec ("%s=%f" % (value, float_input))"

l'esercizio consiste nel scrivere una funzione che chieda all’utente di inserire tre lunghezze, le converta in interi, e le
passi a "is<_ triangle" per verificare se si possa o meno formare un triangolo.

spero qualcuno possa aiutarmi premettendo che sono abbastanza un novizio nel campo della programmazione.

Grazie in anticipo, saluti.
 
Per fortuna mentre ero fuori casa hai repostato il codice indentato! :D
Il problema probabilmente e' il seguente:
L'istruzione exec ("%s=%f" % (value, float_input)) si trova dentro il for, quindi il suo scope e' il for stesso.
Quando tu provi ad accedere alla variabile 'a', il programma non sa cosa sia!

Possibile soluzione:
dichiarare le variabili prima del for, ed assegnare il valore in seguito.
Puoi anche castarlo direttamente nel for! Posto un esempio:

Codice:
def prompt_user():
    prompt = "Please enter side "
    a,b,c = ''
    for value in ['a', 'b', 'c']:
        new_prompt = prompt + value +': ' # modify prompt for value in loop
        my_input = raw_input(new_prompt)   # get input
        float_input = float(my_input)      # convert the entered value to float
        exec ("%s=int(%f)" % (value, float_input))
    
    is_triangle(a,b,c)

Domanda: perche' prima lo salvi come float e non lo casti subito in int?

Fammi sapere se dovessi avere ulteriori problemi!
 
Soluzioni pessime e non idiomatiche sia la tua che quella di fisica-all: exec() ed eval() rientrano nei superficiali stili di programmazione.

Con una list comprehension riesco a fare il tutto in uno e mi attengo alla consegna che hai riportato:
Python:
a, b, c = [ int(n) for n in input("Inserisci i tre lati:").split() ] # scrivi tutto in uno separato da tre spazi es. 6 5 10
is_triangle(a, b, c)

(Traduci nella tua versione di Python.)

Non credo che ti abbiano impartito lezioni di programmazione con exec(), se devi programmare di testa tua con cose che non ti hanno spiegato almeno fallo bene. Poi beh, se mi dovessi sbagliare allora ti consiglio di cambiare corso.
 
Prima di giudicare la qualita' della risposta, ti consiglio vivamente di prenderti una bella camomilla.
Il problema non era la bellezza del codice, ma il fatto che lui non sia riuscito ad apprendere il concetto di scope
Poi ovvio che si puo' scrivere in altri mille modi migliori, lo so anche io, ma se il codice viene scritto e riportato in un modo, non lo stravolgo senza motivo. Avrei potuto chiedere il come mai di queste scelte, vero, ma giudicare una risposta solo perche' non riesci ad adattare una modifica di un codice in una versione non consona non mi sembra un bel atteggiamento
 
Domanda: perche' prima lo salvi come float e non lo casti subito in int?
Non credo che ti abbiano impartito lezioni di programmazione con exec(), se devi programmare di testa tua con cose che non ti hanno spiegato almeno fallo bene. Poi beh, se mi dovessi sbagliare allora ti consiglio di cambiare corso.

Salve di nuovo a tutti;
per rispondere ad entrambi, io sto studiando dal libro think in python per conto mio, questo esercizio ero riuscito a risolverlo specificando variabile per variabile e dato che usciva un codice abbastanza lungo sono andato a vedere le soluzioni, ovvero il codice che ho postato sopra, solo che non capivo perché mi dasse quell'errore; a dir la verità, quindi, inizialmente non mi avevano neanche insegnato exec, %s o %f, erano nelle soluzioni e ho cercato su internet cosa facessero, ma come anche la funzione split(), ve l'ho detto sono un novizio.
In ogni caso grazie ad entrambi per le risposte anche se vorrei saper da fisica-all perché metti nel tuo programma:
perché così, non funziona dato che la funzione is_triangle non ha valori sufficienti per a b c e se provo a metterne 3 tra le virgolette invece mi considera solo quelle e non quelle dell'input.
Grazie ancora
 
Salve di nuovo a tutti;
per rispondere ad entrambi, io sto studiando dal libro think in python per conto mio, questo esercizio ero riuscito a risolverlo specificando variabile per variabile e dato che usciva un codice abbastanza lungo sono andato a vedere le soluzioni, ovvero il codice che ho postato sopra, solo che non capivo perché mi dasse quell'errore; a dir la verità, quindi, inizialmente non mi avevano neanche insegnato exec, %s o %f, erano nelle soluzioni e ho cercato su internet cosa facessero, ma come anche la funzione split(), ve l'ho detto sono un novizio.
In ogni caso grazie ad entrambi per le risposte anche se vorrei saper da fisica-all perché metti nel tuo programma:

perché così, non funziona dato che la funzione is_triangle non ha valori sufficienti per a b c e se provo a metterne 3 tra le virgolette invece mi considera solo quelle e non quelle dell'input.
Grazie ancora
In realta' dovresti scrivere a,b,c = 0,0,0 oppure a,b,c = '', '', '' per esempio, avevo accorciato io per far prima scusami
in questo modo e' come se scrivessi:
a=0
b=0
c=0

pero' invece di occupare 3 righe, fai tutto in una, utile se magari visivamente non vuoi dare troppo impatto a quella variabile (imo)

Si capiva comunque che stessi usando un libro o qualcosa che ti consigliasse/imponesse quelle funzioni, per quello ti ho spiegato una possibile soluzione senza stravolgere il codice. Exec() non e' una funzione che si usa generalmente all'inizio di un corso, pero' ti fa ovviamente onore il fatto che tu l'abbia cercata e "studiata".
Consiglio: piu' cose sai, meglio e'. Meglio conosci il loro campo di utilizzo, meglio e'

P.s. https://www.online-python.com/kUc9bzEiJC ho fatto un test al volo sul codice, ho usato input() invece di raw_input(), ma il risultato e' quello sperato
 
@markito: ti consiglio di leggere le seguenti guide: Come scrivere un codice pythonic / Gli idiomi della programmazione in Python.
Non programmare a caso. La mia era una esortazione a provare a riscrivere il codice fin quando non trovi una soluzione più pulita.

@fisica-all: solo perchè OP è partito col piede sbagliato non vuol dire che tu debba rimuginare sulla cacca. Il problema qui non si circoscrive solo sul "concetto di scope" non compreso, anzi, quello è solo la punta dell'iceberg.
Meglio abituarsi a prendere le giuste abitudini, scrivere un codice fatto in piena regola. Programmare non vuol dire solo scrivere qualcosa che funzioni.
 
sto studiando dal libro think in python per conto mio
Stai studiando python 2, una versione ormai obsoleta del linguaggio. L'ultima major release del linguaggio, python 3, è stata rilasciata la bellezza di 14 anni fa. Visto che stai studiando per conto tuo, ti consiglio ripartire da capo su un libro che parla di python 3. Non ci metterai molto a raggiungere il punto a cui stai ora. Non ho nessun libro da consigliarti, ma se guardi tra i topic in rilievo di questa sezione qualcosa dovresti trovare.

ero riuscito a risolverlo specificando variabile per variabile e dato che usciva un codice abbastanza lungo sono andato a vedere le soluzioni
Soprattutto all'inizio, accorcia solo le parti che vale la pena accorciare: explicit is better than implicit and simple is better than complex. In python 3 potresti scrivere:
Python:
def is_triangle(a,b,c):
    return (a + b > c) and (a + c > b) and (b + c > a)

if __name__ == '__main__':
    a = float(input("insert edge a: "))
    b = float(input("insert edge b: "))
    c = float(input("insert edge c: "))
    print("yes" if is_triangle(a, b, c) else "no")
Non è succinto come quello di nullptr, ma non è incasinato come il tuo. E, soprattutto, non usa nessuna feature inutilmente avanzata.

L'istruzione exec ("%s=%f" % (value, float_input)) si trova dentro il for, quindi il suo scope e' il for stesso.
Il concetto di scope in python è un po' una merd*
Python:
if True:
    a = 7
print(a)   # lecito, stampa 7
Hai quattro livelli di scope (local, enclosing, global e built-in) e due keyword (global e nonlocal). Tutto quello che è all'interno di una funzione è nello scope local, quindi le variabili definite dentro un if (o dentro un for) sono accessibili anche fuori da esso. Quello che è all'interno di una inner function (def dentro un def) è nello scope enclosing. Ciò che è fuori da ogni funzione è nello scope globale e i built-in di python sono nello scope built-in. Quando usi una variabile si applica la LEGB rule: la cerco nel local scope, poi nell'enclosing scope, poi nel global scope e infine nel built-in scope. Tuttavia, se provi a modificare una variabile in uno scope più interno rispetto a quello in cui è stata definita finisci per fare shadowing: ti ritrovi con una nuova variabile che oscura solo temporaneamente quella più esterna. Per risolvere questo problema, in python 3, ci sono le keyword global (modifica una variabile globale) e nonlocal (modifica una variabile locale).
 
  • Mi piace
Reazioni: fisica-all
@markito: ti consiglio di leggere le seguenti guide: Come scrivere un codice pythonic / Gli idiomi della programmazione in Python.
Non programmare a caso. La mia era una esortazione a provare a riscrivere il codice fin quando non trovi una soluzione più pulita.

@fisica-all: solo perchè OP è partito col piede sbagliato non vuol dire che tu debba rimuginare sulla cacca. Il problema qui non si circoscrive solo sul "concetto di scope" non compreso, anzi, quello è solo la punta dell'iceberg.
Meglio abituarsi a prendere le giuste abitudini, scrivere un codice fatto in piena regola. Programmare non vuol dire solo scrivere qualcosa che funzioni.
Ricorda: c'e' sempre modo e modo.
Leggi la risposta del buon @St3ve e prendi esempio per come rispondere in futuro senza giudicare.
Calma ed educazione
 
@fisica-all: il tuo post non è attinente al Python. Potresti evitare di quotarmi per dei post inutili e off-topic?
Io non ho bisogno di prendere spunto proprio da nessuno, le mie sono critiche non personali e totalmente costruttive e sono espresse con educazione. Ognuno è libero di accettarle ed eventualmente rifiutarle, ovviamente a discapito suo.
 
Ultima modifica:
In realta' dovresti scrivere a,b,c = 0,0,0 oppure a,b,c = '', '', '' per esempio, avevo accorciato io per far prima scusami
in questo modo e' come se scrivessi:
a=0
b=0
c=0
oh okok, il punto è però che anche se copio il tuo esatto codice nel mio script, non capisco per quale motivo poi le mie variabili a,b,c rimangono con valore assegnato 0 e quindi non funziona correttamente la funzione is_triangle; mentre se invece scrivo il tuo codice direttamente nell'interprete allora funziona tutto correttamente; idee?

ti consiglio di leggere le seguenti guide: Come scrivere un codice pythonic / Gli idiomi della programmazione in Python.
Non programmare a caso. La mia era una esortazione a provare a riscrivere il codice fin quando non trovi una soluzione più pulita.
oh ok grazie.

Stai studiando python 2,
immagino ti riferisci al fatto che ho usato raw_input() al posto di input() ma tranquillo era solo nelle soluzioni del libro, il libro stesso parla di python 3 e da quello che so è un libro valido per iniziare.
Hai quattro livelli di scope (local, enclosing, global e built-in) e due keyword (global e nonlocal). Tutto quello che è all'interno di una funzione è nello scope local, quindi le variabili definite dentro un if (o dentro un for) sono accessibili anche fuori da esso. Quello che è all'interno di una inner function (def dentro un def) è nello scope enclosing. Ciò che è fuori da ogni funzione è nello scope globale e i built-in di python sono nello scope built-in. Quando usi una variabile si applica la LEGB rule: la cerco nel local scope, poi nell'enclosing scope, poi nel global scope e infine nel built-in scope. Tuttavia, se provi a modificare una variabile in uno scope più interno rispetto a quello in cui è stata definita finisci per fare shadowing: ti ritrovi con una nuova variabile che oscura solo temporaneamente quella più esterna. Per risolvere questo problema, in python 3, ci sono le keyword global (modifica una variabile globale) e nonlocal (modifica una variabile locale).
oh ok grazie penso di aver capito.
 
oh okok, il punto è però che anche se copio il tuo esatto codice nel mio script, non capisco per quale motivo poi le mie variabili a,b,c rimangono con valore assegnato 0 e quindi non funziona correttamente la funzione is_triangle; mentre se invece scrivo il tuo codice direttamente nell'interprete allora funziona tutto correttamente; idee?


oh ok grazie.


immagino ti riferisci al fatto che ho usato raw_input() al posto di input() ma tranquillo era solo nelle soluzioni del libro, il libro stesso parla di python 3 e da quello che so è un libro valido per iniziare.

oh ok grazie penso di aver capito.
Hai ragione, perche' io non ho chiamato exec() in una funzione definita, ma nel __main__
A quanto pare (non sapevo tutte ste cose su exec() ) devi dichiarare le variabili globali e poi aggiungere globals() anche come parametro di exec.

Ecco il tuo codice modificato:

Grazie alla risposta del buon @St3ve dovresti anche riuscire a capire il perche' di questa trafila
 
Ecco il tuo codice modificato:
ah okok grazie , quindi dichiarare le variabili con "global a,b,c" dentro la funzione sarebbe come dichiarare le variabili a,b,c = 0,0,0 fuori dalla def di funzione, e quindi da lì in poi sarebbero trattate come una funzione globale, giusto? grazie ancora
 
immagino ti riferisci al fatto che ho usato raw_input() al posto di input() ma tranquillo era solo nelle soluzioni del libro, il libro stesso parla di python 3 e da quello che so è un libro valido per iniziare.
Oltre al raw_input(), la print senza parentesi e il fatto che tutto il codice che hai postato pare che funzioni correttamente se lo esegui con python 2. Se il libro parla di python 3, non c'è problema. Il tuo codice non funziona perché nella documentazione di exec dicono:
The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.
E nella documentazione di locals dicono:
The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.
Mentre nella documentazione di globals questa nota non c'è. Quindi in python 3 non ti è concesso definire o modificare variabili locali all'interno di exec, in python 2 invece sì perché exec era uno statement invece di una funzione.

ah okok grazie , quindi dichiarare le variabili con "global a,b,c" dentro la funzione sarebbe come dichiarare le variabili a,b,c = 0,0,0 fuori dalla def di funzione, e quindi da lì in poi sarebbero trattate come una funzione globale, giusto? grazie ancora
La cosa più importante da imparare è che exec tipicamente non va usato. Un po' come il goto in altri linguaggi: ha il suo use-case, ma se non sei esperto probabilmente dovresti fingere che non esista. Per global, nonlocal e il concetto di scope in python, io ti consiglio di leggere la spiegazione di qualche guida ben fatta. Probabilmente ne parleranno più avanti nel tuo libro. Più o meno quello che hai scritto è corretto, ma il diavolo è nei dettagli: se usi una variabile vale la regola LEGB che ho accennato in precedenza (la cerco in vari scope finché non la trovo), ma se fai un assegnamento fai shadowing
Python:
a = "global"

def legb_local():
    a = local
    print(a) 

def legb_global():
    print(a) 

def explicit_global():
    global a
    a = "local"
    print(a) 

def error():
    print(a) 
    a = "local"
    print(a) 

print(a)          # global 
legb_local()      # local
print(a)          # global 
legb_global()     # global
explicit_global() # local
print(a)          # local 
error()           # UnboundLocalError: local variable 'a' referenced before assignment
L'ultima funzione va in errore perché sebbene hai una variabile globale, hai anche una variabile locale (che appare alla riga dopo, quindi non ancora inizializzata) che la oscura. Il funzionamento degli scope di python non è comune a quello di molti altri linguaggi, per questo è facile sbagliarsi come è successo a @fisica-all: finché non ti causa qualche problema, ti aspetti che funzioni in modo diverso. Con nonlocal il discorso è praticamente identico.
 
Stato
Discussione chiusa ad ulteriori risposte.