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

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
Avatar utente
nuzzopippo
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1627
Iscrizione: giovedì 12 ottobre 2006, 11:34

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

Messaggio da nuzzopippo »

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, 8:46, modificato 1 volta in totale.
Fatti non foste a viver come bruti ...
Avatar utente
telperion
Rampante Reduce
Rampante Reduce
Messaggi: 5407
Iscrizione: lunedì 10 luglio 2006, 18:20

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

Messaggio da telperion »

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
nuzzopippo
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1627
Iscrizione: giovedì 12 ottobre 2006, 11:34

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

Messaggio da nuzzopippo »

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.
Fatti non foste a viver come bruti ...
Avatar utente
Claudio_F
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1463
Iscrizione: lunedì 28 maggio 2012, 18:49
Desktop: Mate/Gnome
Distribuzione: Ubu22.04

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

Messaggio da Claudio_F »

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
nuzzopippo
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1627
Iscrizione: giovedì 12 ottobre 2006, 11:34

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

Messaggio da nuzzopippo »

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
Fatti non foste a viver come bruti ...
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 9 ospiti