Topic: Aiuto per principiante  (Letto 655 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline DaSguiz

  • python unicellularis
  • *
  • Post: 3
  • Punti reputazione: 0
    • Mostra profilo
Aiuto per principiante
« il: Giugno 19, 2018, 11:51 »
Ciao a tutti,

mi sono approcciato da qualche giorno in questo linguaggio e volevo chiedervi cosa sto sbagliando.
Dovrei creare una funzione che chiede all'utente di inserire i valori di a,b,c e n e che controlli se il teorema di Fermat è verificato o meno.


def fermat():
   if a**n+b**n==c**n:
      print ('è vero!')
   elif a**n+b**n!=c**n:
      print (' no, questo non è vero')            #questa parte dovrebbe essere sbagliata

def main():
   print ('a**n+b**n==c**n')
   a= input('scrivi un numero a= ')
   b=input ('scrivi un numero b= ')
   c= input ('scrivi un numero c= ')
   n=input ('scrivi un numero maggiore di 2= ')
   while int(n)<2:
       print ( " Valore non corretto ")
       print ( " inserisci nuovo valore ")
       n=input ('scrivi un numero maggiore di 2')
   risultato = fermat()
   print (risultato)       #questa parte credo sia giusta


main()



Grazie a tutti
« Ultima modifica: Giugno 19, 2018, 11:57 da DaSguiz »

Offline Legs

  • python unicellularis
  • *
  • Post: 34
  • Punti reputazione: 0
    • Mostra profilo
Re:Aiuto per principiante
« Risposta #1 il: Giugno 19, 2018, 14:04 »
Premessa: sono un programmatore della domenica e quindi prendi quello che ti dico con beneficio di inventario.
Ci sono vari problemi.
Prima di tutto lo scope delle variabili/parametri. Come fa la funzione fermat a sapere quanto valgono a, b, c, n ?
Conviene definire dei parametri veri e propri ad esempio definirei la funzione fermat usando:
def fermat(a0, b0, c0, n0): etc etc
dove a0, b0, c0, n0 rappresentano i parametri di passaggio (ho preferito dargli un nome diverso per evidenziare che sono parametri di passaggio).
Quando chiamerai la funzione dovrai passare a, b, c, n con una chiamata del tipo: fermat(a, b, c, n).
Un altro modo era quello di lavorare con quantità globali senza definire la inutile main().
Però io comunque preferisco usare le variabili locali.
Poi c'è il problema che l'input ti restituisce delle stringhe, non dei numeri. Dovrai quindi fare la conversione in int o float prima di fare dei calcoli.
Altro problema: le lettere accentate. Scusa ma ero abituato a Python 2 e col 3 non ho ancora visto come funziona il discorso.
Da quel che so tutte le stringhe sono in formato utf8 (credo) e quindi non dovrebbero esserci problemi.
Poi io toglierei i print dalla funzione. Meglio restituire solo i valori.
Poi sicuramente gli altri sapranno dirti di più.

A proposito: usa il tasto specifico per riportare il codice sul sito.


« Ultima modifica: Giugno 19, 2018, 15:22 da Legs »

Offline DaSguiz

  • python unicellularis
  • *
  • Post: 3
  • Punti reputazione: 0
    • Mostra profilo
Re:Aiuto per principiante
« Risposta #2 il: Giugno 19, 2018, 15:00 »
Intanto grazie per la risposta!
Riguardo fermat(a,b,c,n), hai perfettamente ragione. Infatti l'ho inserito subito dopo aver pubblicato la richiesta d'aiuto qui sul forum (perchè me l'ero scordato).
Riguardo il fatto delle stringhe e non dei numeri ti riferisci ad :      a=input('scrivi un numero a= ')   ? Come faccio a convertirlo in un numero intero? perchè se metto a=int (input ('scrivi un numero a= ') mi da l'errore...
Comunque riporto il codice e spero di venirne a capo essendo, per ora, l'esercizio più complicato che mi è capitato.


def fermat(a,b,c,n):
if a**n+b**n==c**n:
print ('vero!')
elif a**n+b**n!=c**n:
print ('no, questo non vero')


def main():
print ('a**n+b**n==c**n')
a= input('scrivi un numero a= ')
b= input('scrivi un numero b= ')
c= input('scrivi un numero c= ')
n= input('scrivi un numero maggiore di 2= ')
while int(n)<2:
print ( " Valore non corretto ")
print ( " inserisci nuovo valore ")
n=input ('scrivi un numero maggiore di 2')
risultato = fermat(a,b,c,n)
print (risultato)


main()

« Ultima modifica: Giugno 19, 2018, 15:05 da DaSguiz »

Offline bebo

  • python erectus
  • ***
  • Post: 173
  • Punti reputazione: 0
    • Mostra profilo
    • bebo_sudo's personal homepage
Re:Aiuto per principiante
« Risposta #3 il: Giugno 19, 2018, 18:02 »
Ciao DaSguiz,
benvenuto sul forum e nel mondo di python.

Citazione
Riguardo il fatto delle stringhe e non dei numeri ti riferisci ad :      a=input('scrivi un numero a= ')   ? Come faccio a convertirlo in un numero intero? perchè se metto a=int (input ('scrivi un numero a= ') mi da l'errore...
Non hai ancora detto qual e'/quali sono gli errori che ricevi e che ti stanno bloccando (non e' un numero? hai dimenticato una parentesi?).

Offline Legs

  • python unicellularis
  • *
  • Post: 34
  • Punti reputazione: 0
    • Mostra profilo
Re:Aiuto per principiante
« Risposta #4 il: Giugno 19, 2018, 19:43 »
Riguardo il fatto delle stringhe e non dei numeri ti riferisci ad :      a=input('scrivi un numero a= ')   ? Come faccio a convertirlo in un numero intero? perchè se metto a=int (input ('scrivi un numero a= ') mi da l'errore...
Comunque riporto il codice e spero di venirne a capo essendo, per ora, l'esercizio più complicato che mi è capitato.
Mi fa piacere che hai già messo mano al codice. Sicuramente come ti è già stato fatto notare avrai dimenticato una parentesi.
Ho rimesso mano anche io al tuo codice e ho fatto qualche modifichetta per riportarlo a una forma che mi piace un po' di più.
def fermat(a0, b0, c0, n0):
   if a0**n0 + b0**n0 == c0**n0:
      return 'Vero!'
   else:
      return 'Non vero'
 
if __name__ == '__main__':

print ('a**n+b**n==c**n')
a = int(input('scrivi un numero a = '))
b = int(input('scrivi un numero b = '))
c = int(input('scrivi un numero c = '))
n = int(input('scrivi un numero maggiore di 2 = '))

while n < 2:
print( 'Non corretto')
print( 'Inserisci un nuovo valore ')
n = int(input('Scrivi un numero maggiore di 2'))

print(fermat(a, b, c, n))

A me sembra che funzioni.
L'unica cosa importante che ho modificato è l'if nella funzione di fermat. Mi sembrava ridondante il doppio controllo.
Se invece c'è una terza possibilità allora è giusto rimettere il tuo controllo ma aggiungere anche un else per la terza possibilità.

La riga:
if __name__ == '__main__':
dice al programma di eseguire il codice solo se lo fai partire come programma. In questo modo se decidessi di usare import quel pezzo di codice non verrebbe eseguito ma avresti la definizione della funzione fermat disponibile.

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.821
  • Punti reputazione: 9
    • Mostra profilo
Re:Aiuto per principiante
« Risposta #5 il: Giugno 19, 2018, 19:59 »
In python una funzione restituisce impicitamente None se non le fai restutuire esplicitamente qualcosa. Quindi assegnare il valore di ritorno a una funzione che non ha un valore di ritorno esplicito è sempre possibile per carità, ma è anche perfettamente inutile: lo sai già, qual è il "risultato", in ogni caso.

Davvero, il consiglio in questi casi è sempre lo stesso, ed è sempre quello giusto, ed è sempre quello che nessuno segue mai. Se vuoi imparare python segui un buon libro, non andare alla cieca per tentativi. Da queste parti si consiglia sempre il Lutz, ed è un buon consiglio.


(@Legs: d'accordo, "funziona" se vogliamo dirla così. Ma se vogliamo aiutare, facciamolo in modo corretto. Non scriviamo cose orrende tipo "return Vero!, return Non Vero", dai... Anche se adesso l'OP è impegnato a capire altre cose, magari se tu gli fai vedere fin da subito il pattern corretto, lui in futuro sarà più invogliato ad imitarlo, capisci. E stessa cosa per quel ciclo while)

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.447
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re:Aiuto per principiante
« Risposta #6 il: Giugno 19, 2018, 21:15 »
E a nessuno e' venuto in mente che l'unica cosa sensata per la funzione fermat e' ritornare un booleano?

Offline Legs

  • python unicellularis
  • *
  • Post: 34
  • Punti reputazione: 0
    • Mostra profilo
Re:Aiuto per principiante
« Risposta #7 il: Giugno 19, 2018, 23:20 »
(@Legs: d'accordo, "funziona" se vogliamo dirla così. Ma se vogliamo aiutare, facciamolo in modo corretto. Non scriviamo cose orrende tipo "return Vero!, return Non Vero", dai... Anche se adesso l'OP è impegnato a capire altre cose, magari se tu gli fai vedere fin da subito il pattern corretto, lui in futuro sarà più invogliato ad imitarlo, capisci. E stessa cosa per quel ciclo while)
Hai perfettamente ragione.

Offline DaSguiz

  • python unicellularis
  • *
  • Post: 3
  • Punti reputazione: 0
    • Mostra profilo
Re:Aiuto per principiante
« Risposta #8 il: Giugno 20, 2018, 08:46 »
Grazie a tutti,

Sto seguendo il libro ''Pensare in Python'' visto che è stato consigliato da molti...

Offline Legs

  • python unicellularis
  • *
  • Post: 34
  • Punti reputazione: 0
    • Mostra profilo
Re:Aiuto per principiante
« Risposta #9 il: Giugno 20, 2018, 10:13 »
Comunque credo che RicPol e riko intendessero modificare la funzione in questo modo:
def fermat(a0, b0, c0, n0):
return a0**n0 + b0**n0 == c0**n0

restituisce True se la terna soddisfa la condizione False in caso opposto.
L'ho anche verificato con la terna pitagorica (3,4,5 con esponente 2) e con altre e restituisce i valori giusti.

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.821
  • Punti reputazione: 9
    • Mostra profilo
Re:Aiuto per principiante
« Risposta #10 il: Giugno 20, 2018, 14:39 »
> Comunque credo che RicPol e riko intendessero modificare la funzione in questo modo:
> (...)

Proprio così. Ma se uno ha paura che per un principiante questa notazione sia un po' troppo "compatta", al limite va benissimo anche scrivere:

def fermat(a, b, c, n):
    if a**n + b**n == c**n:
        return True
    else:
        return False

E' più prolisso ma comunque corretto, e l'OP può passare successivamente alla forma "compatta" non appena si rende conto che il valore dell'espressione nell'"if" è *già* il valore che vale la pena di restituire.
L'importante è che l'api della funzione si conformi alla più ovvia consuetudine del linguaggio usato per compiti del genere. Voglio dire, se questo fosse C, allora restituiresti 0 per falso e 1 per vero. 

Oh, e a proposito, proprio non saprei perché bisogna chiamare le variabili "a0", "b0"... boh?

Offline Legs

  • python unicellularis
  • *
  • Post: 34
  • Punti reputazione: 0
    • Mostra profilo
Re:Aiuto per principiante
« Risposta #11 il: Giugno 20, 2018, 14:50 »
Oh, e a proposito, proprio non saprei perché bisogna chiamare le variabili "a0", "b0"... boh?
E' solo una mia fisima. Non pensarci troppo.
Ma invece per la parte sull'input di n come lo avresti risolto?
Per dire, una cosa del genere ti sembra troppo prolissa?
while True:
n = int(input(' n ( >=2 ) = '))
if n >= 2:
break
print('n non deve essere minore di 2')

Qual è la via Pythonica per farlo?

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.821
  • Punti reputazione: 9
    • Mostra profilo
Re:Aiuto per principiante
« Risposta #12 il: Giugno 20, 2018, 19:10 »
Ma non è che ci sia una "via pythonica" per farlo. Io onestamente pensavo solo, come minimo assoluto indispensabile, di non scrivere cose come

   n = int(input('scrivi un numero maggiore di 2 = '))
   while n < 2:
      print( 'Non corretto')
      print( 'Inserisci un nuovo valore ')
      n = int(input('Scrivi un numero maggiore di 2'))

per non ripetere due volte lo stesso messaggio (che infatti scrivi già in due modi diversi, a dimostrazione lampante della fragilità di questo sistema).
La stessa cosa, scritta così:

   while True:
      n = int(input('Scrivi un numero maggiore di 2'))
      if n >= 2:
          break
      print('non corretto, bla bla bla')

è già un piccolo passo avanti verso un codice che non fa sanguinare gli occhi quando lo leggi.

Poi intendiamoci, il design di una CLI interattiva è Difficile. Francamente, per queste cose è meglio usare una gui. Però certo, ci sono situazioni in cui può aver senso anche la cli interattiva.
Detto questo, va bene anche scrivere cose del genere, purché sia chiaro che sono delle scorciatoie fragili e che non ci stiamo ponendo i problemi che una cli interattiva "seria" dovrebbe porsi.
Ma va bene, sia chiaro. Un principiante non dovrebbe porsi il problema del design di una cli interattiva. Per me è più che sufficiente che il principiante impari per lo meno a separare la parte di I/O dalla funzione vera e propria. A non fare cose del tipo

def fermat(a, b, c, n):
    a = int(input('....'))
   .....

Ecco, è quando vedo queste cose che proprio mi si drizzano i capelli.
« Ultima modifica: Giugno 20, 2018, 19:13 da RicPol »

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.447
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re:Aiuto per principiante
« Risposta #13 il: Settembre 23, 2018, 22:21 »
Poi intendiamoci, il design di una CLI interattiva è Difficile. Francamente, per queste cose è meglio usare una gui. Però certo, ci sono situazioni in cui può aver senso anche la cli interattiva.
Detto questo, va bene anche scrivere cose del genere, purché sia chiaro che sono delle scorciatoie fragili e che non ci stiamo ponendo i problemi che una cli interattiva "seria" dovrebbe porsi.

Sono in vena di necro-posting... per qualche motivo il forum mi ha indicato questo post e ci ho trovato questa gemma (come spunto).

Quello che succede e' che i principianti vogliono scrivere un programma. E sono semplicemente contenti di vederlo girare. Non si pongono il problema che sia "piacevole". Non si pongono nemmeno il problema che sia robusto o corretto: sono gia' contenti di vedere qualcosa scritto da loro che funziona (per la loro definizione di funziona).

Ovviamente scrivere una cli con parametri sensati e' piu' facile e c'e' rischio che sia piu' comodo. In realta' tante classi di programmi "seri" funzionano cosi'. Perche' e' una cosa che, anche nel 2018, ha senso fare.
Non va bene per tutto, non prova ad andare bene per tutto e non ti illude che vada bene per tutto. Pero' e' qualcosa. E' piu' semplice e piu' longevo.

Pero' i principianti odierni tipicamente non hanno una lunga esposizione a unix (che presenta numerosi esempi di programmi usati tutti i giorni che funzionano cosi'), perche' ovviamente se anche usano Linux non usano quotidianamente quella parte. Non usano tanto il terminale (che avrebbero anche su Windows, anche se in qualche modo meno prominentemente -- le features adesso ci sono quasi tutte eh...). Il che vuole dire che l'unico esempio di interfaccia che conoscono e' quella "grafica" e siccome non hanno ancora un toolkit fanno una cosa interattiva ma testuale (che guarda caso e' strettamente piu' scomoda di una GUI e di una cli vera, e, in un certo senso, piu' complicata di entrambe).

Poi ovviamente si arriva al nocciolo della questione: per assurdo oggi ci sono piu' tool e piu' documentazione. Ma "entrare" in un sistema e' piu' complicato. Gli home computer degli anni 80 avevano in generale solo un merdoso basic, ma era estremamente immediato. E dava accesso a quasi tutto quasi immediatamente. E per il resto c'era tipicamente il codice macchina (che a volte si poteva quasi embeddare nel basic). Le GUI complicano tutto: la learning curve e' strettamente piu' ripida e in effetti richiedono piu' concetti avanzati. In particolare, senza un po' di OOP si fa *fatica* a comprendere certe cose. Sono anche programmi intrinsecamente piu' complicati ("eventi", "gestione dell'errore") e quindi tutte le tecniche di software engineering per semplificare la vita diventano preziose quasi subito.

E noi cerchiamo di "insegnare a sviluppare software" a persone che invece mirano a vedere un programma che stampa "hello world". Noi "sappiamo" che appena oltre l'hello world questo detour fa risparmiare tempo. Ma viviamo ai tempi della 1 hour delivery (in certi posti). Io ero contento quando un libro mi arrivava in una settimana.

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.821
  • Punti reputazione: 9
    • Mostra profilo
Re:Aiuto per principiante
« Risposta #14 il: Settembre 24, 2018, 17:07 »
Uhm, sì con qualche punta di no.
Intanto conviene tenere separati i concetti di "cli" e "cli interattiva". In questo thread di parlava di cli interattiva, in realtà. La "cli pura, unix-style" non è uno strumento per utenti finali, e quando ne fai il design non devi tener conto di una marea di problemi di user interaction. Per dire, se sbagli un flag, se il parametro non è del tipo giusto... si pianta e muore lì. Una cli "pura" è questa roba qui, per capirci: https://xkcd.com/1168/.

Una cli interattiva è già più simile a una gui, nel senso che il target è più simile, e i problemi di design connessi sono anche più simili. Cli interattive sono "django-startproject" o "sphix-quickstart" o cose del genere.
Ora, se il problema è "il principiante vuole vedere il programma che gira", allora probabilmente il principiante sta pensando a una cli interattiva, non una cli "pura". E sovente è anche giusto così: è difficile che il principiante abbia scritto un programma per cui ha senso pensare a una cli "pura" come interfaccia. Il principiante scrive programmi come def somma(a, b): return a+b. Non sono convinto che una buona interfaccia per questo script sia $ python myscript.py 12 18.
Quindi no, non credo che la minore esposizione a unix sia una seria aggravante per il problema in questione. Avere esperienza di unix ti porta ad architettare delle cli eleganti, non necessariamente delle cli interattive. Vero è comunque che se il principiante non riesce a "vedere" oltre le gui, allora abbiamo un problema.

Sulle cli interattive, quindi. Per cominciare, è chiaro che qui stiamo parlando dal punto di vista della *didattica* di Python.
Ora, quello che io vorrei che il principiante capisse, è sostanzialmente questo: non ti *serve* una cli interattiva. Lascia perdere. Non usare "input", punto. Una cli interattiva è una user interface, e come tale è un compito di programmazione complesso e separato. Hai fatto uno script def somma(a, b): return a+b e vuoi "vederlo girare"? Allora fa' così che è meglio:

def somma(a, b):
    return a+b

# meglio ancora in un blocco __main__, ma stai a guardar capello
a = 4
b = 2
res = somma(a, b)
print(res)

Quando vuoi provarlo con dei parametri diversi, apri lo script e cambia i valori. E così via. Tutto qua. Se il tuo script *non* ha un utente (perché è un esercizio, perché è una prova, perché sei un principiante), allora *non* preoccuparti dell'interfaccia utente. Nel mio manuale ideale, "print" è introdotto dopo una cinquantina di pagine, e "input" è un argomento avanzato che non compare prima di pagina 200.

Ora, mi rendo conto che didatticamente è una posizione un po' nazista. A lato pratico, se il principiante vuole buttar giù due "input" per "vedere lo script che gira", mah, faccia pure. Il problema però è che non appena il principiante pensa "adesso ci metto un input", ecco che *immediatamente* cominci a vedere che lo script diventa:

def somma():
    a = int(input('inserisci il primo numero'))
    b = int(input('e adesso il secondo'))
    res = a+b
    print('il risultato e', res)

somma()

E a questo punto sei fottuto. Il tempo che ci metti a spiegare perché questa cosa non va bene... didatticamente fai prima a dire "non usare input". Nazi è comodo.

E il guaio è che le cose peggiorano rapidamente, perché la cli interattiva è per il principiante come la carta moschicida per le mosche. E' facile toccarla, e una volta toccata non ne esci più vivo. Allora il principiante comincia a dire che cosa succede se non mette un numero, e allora poi bisogna far provare tre volte l'utente, e poi forse dopo la prima somma vuole farne un'altra... Inizia insomma a porsi dei problemi di user interaction: problemi *legittimi*, visto che quella che sta facendo è una cli interattiva. Ma problemi che lo distolgono dal focus di quello che dovrebbe imparare, e per i quali non ha ancora nessuna esperienza.

Così senza pensarci troppo, direi che scrivere cli interattive per un principiante è dannoso perché:
1) ti indirizza a una non-idea sui test: siccome posso "far girare il programma" mettendo ogni volta valori diversi, allora *questo* vuol dire testare il programma. Nel mio manuale non si introduce "input" prima di introdurre il concetto di test.
2) la logica della cli percola inevitabilmente nella logica (di business) del programma: e questo, attenzione, è inevitabile o quasi, perché come sappiamo il modo per evitarlo sarebbe possedere il concetto di 3-tier architecture, e sei già in acque profondissime per il principiante. Così, nell'attesa, ti rassegni a sporcare il codice. Ma una volta che il principiante si abitua a sporcare il codice, è già fottuto.
3) gli errori della cli si sommano agli errori del programma, e (siccome ovviamente il principiante non scrive test) quando qualcosa non funziona è sempre più difficile dire quando l'errore è nella logica del programma, o quando è semplicemente un problema nella cli
4) il tempo e le energie che il principiante dedica alla cli finiscono per superare quelle dedicate al programma
5) la cli è sempre più verbosa del programma, che diventa più difficile da leggere e da gestire per il principiante. La cli è inevitabilmente accoppiata al programma, cosa che ne complica la gestione: quando aggiungi un parametro ti devi portare dietro anche tutte le modifiche necessarie della cli, etc.
6) quando, con fatica e andando a tentoni, sei riuscito a crearti un "pattern" per aggiungere le cli interattive ai tuoi script di esercizio, allora... hai cementato nel tuo cervello il modo sbagliato per scrivere le cli, e questo ti danneggerà poi quando davvero dovrai imparare a porti il problema delle interfacce utente (validazione dei dati, annullare e tornare indietro, pluri-linguismo, persistenza delle impostazioni, tutta la psicologia della user experience, bla bla bla).

Insomma, sono contro le cli, le cli interattive, le gui e le interfacce telepatiche. I principianti dovrebbero essere gentilmente sospinti a impiegare meglio il proprio tempo.