[Risolto][Python] 2 Vs 3 : costr. "if var in lista" diff.

Linguaggi di programmazione: php, perl, python, C, bash, ecc.

[Risolto][Python] 2 Vs 3 : costr. "if var in lista" diff.

Messaggioda nuzzopippo » domenica 12 marzo 2017, 11:51

Salve, cercando di comprendere il python sto seguendo il testo, in italiano, "pensare da informatico", scritto per la versione 2 del linguaggio, per comprendere gli esempi eseguo dei test tanto nello idle versione 2.7 quanto nella versione 3-3.5, per intercettare eventuali differenze funzionali.

nella prosecuzione degli esempi mi sono imbattuto in questo stralcio di codice :
Codice: Seleziona tutto
class ManoOldMaid(Mano):

   def RimuoveCoppie(self):
      Conteggio = 0
      CarteOriginali = self.Carte[:]
      for CartaOrig in CarteOriginali:
         CartaDaCercare = Carta(3-CartaOrig.Seme, CartaOrig.Rango)
         if CartaDaCercare in self.Carte:
            self.Carte.remove(CartaOrig)
            self.Carte.remove(CartaDaCercare)
            print("Mano di %s : %s elimina %s" % (self.Nome, CartaOrig, CartaDaCercare))
            Conteggio = Conteggio + 1
         
      return Conteggio


perfettamente funzionale nella versione 2.7, stralcio di output in tale versione :
Codice: Seleziona tutto
>>> partita = GiocoDiCarte()
>>> mano1 = ManoOldMaid('Franco')
>>> partita.Mazzo.Distribuisci([mano1], 13)
>>> print mano1
La mano di Franco contiene queste carte:
6 di Picche
 Regina di Cuori
  Regina di Fiori
   9 di Fiori
    5 di Picche
     3 di Picche
      10 di Quadri
       7 di Cuori
        5 di Cuori
         7 di Picche
          9 di Picche
           Re di Fiori
            6 di Quadri

>>> mano1.RimuoveCoppie()
Mano di Franco : 9 di Fiori elimina 9 di Picche
1
>>>


ma non funzionante nella versione 3 di python, il costrutto "if CartaDaCercare in self.Carte:" NON funziona per la selezione, dalla documentazione della versione 3, che ho compreso poco, vedo che tal genere di costrutti "dovrebbero" essere tuttora validi per verifiche decisionali ma non si comprende in qual modo siano applicabili, tentativi del genere :
Codice: Seleziona tutto
if (CartaDaCercare in self.Carte):
if (CartaDaCercare in self.Carte) == True:
if (CartaDaCercare in self.Carte) == 0:

si son rivelati inefficaci, se non fonte di errore.

Essendo un costrutto di rilevante importanza, son certo che esiste un metodo funzionale valido che molti di voi avranno certamente trovato, anche se a me non sta riuscendo, quindi :
1 - come si fa?
2 - esiste una docs (magari in italiano, anche se ci spero poco) sulle differenze significative tra le due versioni di python?
Ultima modifica di nuzzopippo il lunedì 13 marzo 2017, 9:46, modificato 1 volta in totale.
Avatar utente
nuzzopippo
Scoppiettante Seguace
Scoppiettante Seguace
 
Messaggi: 924
Iscrizione: ottobre 2006

Re: [Python] 2 Vs 3 : costr. "if var in lista" diff. funzion

Messaggioda telperion » domenica 12 marzo 2017, 13:35

c'è un tool che si chiama
2to3
che analizza file python2 e suggerisce le modifiche

Codice: Seleziona tutto
mc@debian64:~/torrent$ 2to3 cont.py

RefactoringTool: Refactored cont.py
--- cont.py     (original)
+++ cont.py     (refactored)
@@ -8,7 +8,7 @@
                        if CartaDaCercare in self.Carte:
                                self.Carte.remove(CartaOrig)
                                self.Carte.remove(CartaDaCercare)
-                               print("Mano di %s : %s elimina %s" % (self.Nome, CartaOrig, CartaDaCercare))
+                               print(("Mano di %s : %s elimina %s" % (self.Nome, CartaOrig, CartaDaCercare)))
                                Conteggio = Conteggio + 1
         
        return Conteggio
RefactoringTool: Files that need to be modified:
RefactoringTool: cont.py



es:
Codice: Seleziona tutto
class ManoOldMaid(Mano):

   def RimuoveCoppie(self):
      Conteggio = 0
      CarteOriginali = self.Carte[:]
      for CartaOrig in CarteOriginali:
         CartaDaCercare = Carta(3-CartaOrig.Seme, CartaOrig.Rango)
         if CartaDaCercare in self.Carte:
            self.Carte.remove(CartaOrig)
            self.Carte.remove(CartaDaCercare)
            #print("Mano di %s : %s elimina %s" % (self.Nome, CartaOrig, CartaDaCercare))
            print(("Mano di %s : %s elimina %s" % (self.Nome, CartaOrig, CartaDaCercare)))
            Conteggio = Conteggio + 1
        return Conteggio



poi OCCHIO, python3 vuole le identazioni PRECISE 4 spazi (o 8 )
l'identazione del tag code del forum non è corretta.
Avatar utente
telperion
Rampante Reduce
Rampante Reduce
 
Messaggi: 5254
Iscrizione: luglio 2006

Re: [Python] 2 Vs 3 : costr. "if var in lista" diff. funzion

Messaggioda nuzzopippo » domenica 12 marzo 2017, 15:25

Grazie della risposta @telperion

Purtroppo, il problema non è li, dato che il test in questione non viene mai superato quella istruzione in se non viene mai eseguita, comunque anche ricodificandola secondo le indicazione di 2to3 si ha :
Codice: Seleziona tutto
>>> class ManoOldMaid(Mano):

   def RimuoveCoppie(self):
      Conteggio = 0
      CarteOriginali = self.Carte[:]
      for CartaOrig in CarteOriginali:
         CartaDaCercare = Carta(3-CartaOrig.Seme, CartaOrig.Rango)
         if CartaDaCercare in self.Carte:
            self.Carte.remove(CartaOrig)
            self.Carte.remove(CartaDaCercare)
            print(("Mano di %s : %s elimina %s" % (self.Nome, CartaOrig, CartaDaCercare)))
            Conteggio = Conteggio + 1

      return Conteggio

   
>>> partita = GiocoDiCarte()
>>> mano1 = ManoOldMaid('Franco')
>>> partita.Mazzo.Distribuisci([mano1], 13)
>>> print(mano1)
La mano di Franco contiene queste carte:
Regina di Fiori
 Regina di Cuori
  2 di Fiori
   3 di Quadri
    3 di Cuori
     9 di Picche
      10 di Picche
       7 di Picche
        6 di Fiori
         2 di Picche
          Jack di Cuori
           4 di Cuori
            7 di Cuori

>>> mano1.RimuoveCoppie()
0
>>>

Per altro, ho provato a passare l'intero insieme del codice con 2to3 e quella da Te fornita è l'unica indicazione che si riceve, il resto "sarebbe" coerente con la sintassi 3.x

Personalmente ho il dubbio che sia variata l'interazione con gli oggetto nei costrutti "IF ... IN ... ELSE", in effetti per tali costrutti vengono esemplificati solo variabili di tipo primitivo nella documentazioni, mai oggetti e liste di oggetti.

Per altro, mi viene il dubbio possa essere il metodo "__cmp__" della classe "Carta", sotto riportato
Codice: Seleziona tutto
   def __cmp__(self, Altro):
      
      # controlla il seme
      if self.Seme > Altro.Seme: return 1
      if self.Seme < Altro.Seme: return -1
      
      # se i semi sono uguali controlla il rango
      if self.Rango == "Asso" and Altro.Rango != "Asso": return 1
      if self.Rango > Altro.Rango: return 1
      if self.Rango < Altro.Rango: return -1
      
      # se anche i ranghi sono uguali le carte sono uguali
      return 0

a poter dare risultati equivoci con la sintassi della versione 3 di python ... forse serve approfondire la questione, ma tale metodo NON viene indicato nei suggerimenti del tools utilizzato.

Il codice completo di riferimento si trova nel testo "Pensare da informatico", all'occorrenza posso riportarlo per intero, non l'ho fatto per non appesantire il post.

[Edit] è da notare che nella esecuzione in IDLE 3.5 non viene rilasciata alcuna eccezione.

[Ri_Edit] - Forse meriterebbe un post tutto suo, credo di aver risolto la faccenda ma prima di chiudere il post gradirei il conforto di utenti più esperti sulla faccenda.

la implementazione di "__cmp__" sopra da me indicata mi ha fatto pensare, in effetti i valori boleani dal 2 al 3 sono cambiati da "0" e "1" a "True" e "False", andando a vedere tra gli operatori implementabili negli oggetti python vi è l'operatore "__eq__", reimplementando la classe "Carta" del testo in questa maniera :
Codice: Seleziona tutto
>>> class Carta:

   ListaSemi = ["Fiori", "Quadri", "Cuori", "Picche"]
   ListaRanghi = ["impossibile", "Asso", "2", "3", "4", "5", "6",\
               "7", "8", "9", "10", "Jack", "Regina", "Re"]

   def __init__(self, Seme=0, Rango=0):
      self.Seme = Seme
      self.Rango = Rango

   def __str__(self):
      return (self.ListaRanghi[self.Rango] + " di " +
            self.ListaSemi[self.Seme])

   def __cmp__(self, Altro):

      # controlla il seme
      if self.Seme > Altro.Seme: return 1
      if self.Seme < Altro.Seme: return -1

      # se i semi sono uguali controlla il rango
      if self.Rango == "Asso" and Altro.Rango != "Asso": return 1
      if self.Rango > Altro.Rango: return 1
      if self.Rango < Altro.Rango: return -1

      # se anche i ranghi sono uguali le carte sono uguali
      return 0

   def __eq__(self, Altro):
      if self.Seme == Altro.Seme and self.Rango == Altro.Rango:
         return True
      return False


Si ha una corretta identificazione tramite la clausola "IN", da un test "al volo" :
Codice: Seleziona tutto
>>> carte = []
>>> carta1 = Carta(0, 1)
>>> carte.append(carta1)
>>> carta2 = Carta(0, 2)
>>> carte.append(carta2)
>>> carta3 = Carta(0, 3)
>>> carte.append(carta3)
>>> cartaR = Carta(0, 2)
>>> if cartaR in carte:
   print(('%s è presente nel mazzo' % (cartaR)))
else:
   print(('%s NON è presente nel mazzo' % (cartaR)))

   
2 di Fiori è presente nel mazzo
>>>


Mi appare evidente che implementare la sola funzione "__cmp__", già sufficiente per python 2, è ora insufficiente in python 3 ove è necessario implementare l'eguaglianza tra gli oggetti.

Spero in un pronunziamento da parte degli utenti addentrati nella materia.
Avatar utente
nuzzopippo
Scoppiettante Seguace
Scoppiettante Seguace
 
Messaggi: 924
Iscrizione: ottobre 2006

Re: [Python] 2 Vs 3 : costr. "if var in lista" diff. funzion

Messaggioda Claudio_F » domenica 12 marzo 2017, 20:31

Complimenti per aver trovato il colpevole :) Si parla di overloading degli operatori, argomento avanzato per i tutorial di base. In effetti __cmp__ nella 3.x non esiste più, quindi tutti i confronti di uguaglianza/appartenenza chiamano implicitamente __eq__ . Se scrivi dir(oggetto) vedi gli attributi disponibili.

Non me ne ero mai accorto perché nel mio uso base del linguaggio non mi sono mai trovato a dover confrontare con i normali operatori 'in' e '==' oggetti creati da me.

Per quanto riguarda True/False vs 1/0, sotto sotto sono sempre interi:
Codice: Seleziona tutto
>>> True + 1
2
>>> False + 1
1
>>> True + True
2
Avatar utente
Claudio_F
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1279
Iscrizione: maggio 2012
Desktop: Unity/Mate
Distribuzione: Ubuntu14.04/Mint17

Re: [Python] 2 Vs 3 : costr. "if var in lista" diff. funzion

Messaggioda nuzzopippo » lunedì 13 marzo 2017, 9:45

Grazie, solo una intuizione fortunata :)

Buoni i chiarimenti, non avevo compreso la mancanza di __cmp__ in python 3

In ogni caso, l'operatore IN è potenzialmente molto utile in un ciclo decisionale, buona cosa aver capito il suo utilizzo con gli oggetti, ringrazio gli intervenuti e metto risolto
Avatar utente
nuzzopippo
Scoppiettante Seguace
Scoppiettante Seguace
 
Messaggi: 924
Iscrizione: ottobre 2006


Torna a Programmazione

Chi c’è in linea

Visualizzano questa sezione: 0 utenti registrati e 7 ospiti