Je code un jeu du pendu dans une fenêtre avec tkinter, en utilisant des images.
Mais lorsque j'exécute le code, j'obtients ça :
Traceback (most recent call last):
File "<string>", line 420, in run_nodebug
File "<module1>", line 101, in <module>
File "<module1>", line 74, in affichemot
File "<module1>", line 66, in affichemot
AttributeError: 'function' object has no attribute 'upper'
Pourtant le code m'a l'air bon ?
# Créé par Mazzeo Roberto, le 08-11-2016 en Python 3.4
from tkinter import *
from random import *
# Fonctions utiles
def trouvermot() : # Le fichier 'liste.txt' comporte 881 mots
nbr = randint(1,881) # Cette fonction choisit un mot au hasard parmi les 881 mots présents
i = 0
fichier = open("G:\\Python\\Livre\\Images\\Projet 5\\liste.txt","r")
while i != nbr :
mot = fichier.readline().replace("\n","")
i = i + 1
if len(mot) < 5 : # Mais le mot choisit doit être composé de plus de 5 lettres, sinon c'est trop facile à trouver
while i != nbr :
mot = fichier.readline().replace("\n","")
i = i + 1
fichier.close()
return mot.upper()
def affichemot(mot,lettre):
# Première partie de la fonction
global nbessais # La première partie actualise l'image du pendu en fonction du nombre d'essais restants du joueur
nbessais = nbessais - 1 # A chaque clic sur le bouton "proposer" (voir ligne 102), le nombre d'essais restant diminue
if nbessais == 8 :
img1 = PhotoImage(file = "G:\\Python\\Livre\\Images\\Projet 5\\bonhomme1.gif") # L'image convenant au nombre d'essais restant est affichée
Canv.itemconfig(ImagePendu, image = img1)
Canv.update()
elif nbessais == 7 :
img2 = PhotoImage(file = "G:\\Python\\Livre\\Images\\Projet 5\\bonhomme2.gif")
Canv.itemconfig(ImagePendu, image = img2)
Canv.update()
elif nbessais == 6 :
img3 = PhotoImage(file = "G:\\Python\\Livre\\Images\\Projet 5\\bonhomme3.gif")
Canv.itemconfig(ImagePendu, image = img3)
Canv.update()
elif nbessais == 5 :
img4 = PhotoImage(file = "G:\\Python\\Livre\\Images\\Projet 5\\bonhomme4.gif")
Canv.itemconfig(ImagePendu, image = img4)
Canv.update()
elif nbessais == 4 :
img5 = PhotoImage(file = "G:\\Python\\Livre\\Images\\Projet 5\\bonhomme5.gif")
Canv.itemconfig(ImagePendu, image = img5)
Canv.update()
elif nbessais == 3 :
img6 = PhotoImage(file = "G:\\Python\\Livre\\Images\\Projet 5\\bonhomme6.gif")
Canv.itemconfig(ImagePendu, image = img6)
Canv.update()
elif nbessais == 2 :
img7 = PhotoImage(file = "G:\\Python\\Livre\\Images\\Projet 5\\bonhomme7.gif")
Canv.itemconfig(ImagePendu, image = img7)
Canv.update()
elif nbessais == 1 : # Lorsque le joueur atteind le dernier essai, il a perdu
img8 = PhotoImage(file = "G:\\Python\\Livre\\Images\\Projet 5\\bonhomme8.gif")
Canv.itemconfig(ImagePendu, image = img8)
Canv.update()
ecriture.config(text = "Vous avez perdu !") # Le Label 'ecriture' est actualisé
EssaisRestant.place_forget() # Les widgets devenus inutiles sont supprimés
EntreeProp.place_forget()
ValidationProp.place_forget()
EssaisRestant.config(text = "Il vous reste " + str(nbessais) + " essais") # Ce label donne le nombre
# d'essais qu'il reste au joueur
# (actualisé à chaque clic sur le bouton "proposer")
# Deuxième partie de la fonction
r = ""
for i in range(len(mot)) : # Affichage du mot au fur et a mesure que le joueur donne ses propositions de lettres
if lettre.upper().count(mot.upper()[i]) > 0 :
r = r.upper() + mot.upper()[i] + " "
else :
r = r.upper() + "_" + " "
if lettre.upper() not in mot.upper() : # Le programme dit si la lettre est ou non dans le mot
ecriture.config(text = "La lettre '" + lettre.upper() + "' n'est pas dans le mot")
else :
ecriture.config(text = "La lettre '" + lettre.upper() + "' est pas dans le mot !")
AffichageMot.config(text = affichemot(mot, EntreeProp.get))
return r
fen = Tk() # Création de la fenêtre, avec options
fen.title("Jeu du pendu")
fen.geometry("800x400")
fen.resizable(width = False, height = False)
nbessais = 9 # Déclaration des variables
mot = trouvermot()
aidemot = mot[0]
Canv = Canvas(fen, width = 1500, height = 720, bg = "#3E3F3F") # Création du Canvas
Canv.place(x = -2, y = -2)
img = PhotoImage(file = "G:\\Python\\Livre\\Images\\Projet 5\\bonhomme1.gif") # Affichage du bonhomme pendu au départ
ImagePendu = Canv.create_image(450, 50, image = img, anchor = 'nw')
EntreeProp = Entry(fen, width = 10) # Création de l'entrée pour entrer la proposition
EntreeProp.place(x = 100, y = 250)
EntreeProp.focus() # Force le curseur a être dans l'entry 'EntreeProp' pour que le joueur n'ai pas besoin de cliquer dessus
ecriture = Label(fen, text = "Entrez une lettre", font = ("Arial", 20), bg = "#3E3F3F", fg = "White")
ecriture.place(x = 40, y = 140 )
EssaisRestant = Label(fen, text = "Il vous reste " + str(nbessais) + " essais", bg = "#3E3F3F", fg = "White") # Création des labels utiles
EssaisRestant.place(x = 150, y = 350)
AffichageMot = Label(fen, font=("Arial", 20), bg="#3E3F3F", fg="White")
AffichageMot["text"] = affichemot(mot, aidemot)
AffichageMot.place(x=100, y=50)
ValidationProp = Button(fen, text = "Proposer", command = lambda : affichemot(mot, EntreeProp.get)) # Création du bouton pour confirmer la proposition
ValidationProp.place(x = 210, y = 246)
fen.mainloop()
C'est EXACTEMENT la même erreur que dans l'un de tes précédents sujet
La fonction affichemot utilise la variable EssaisRestant. Or cette variable est définies en ligne 96 ALORS QUE tu exécutes la fonction en ligne 94, donc avant la création de la variable (d'où l'erreur).
Si possible, essaie de mettre à la suite ton nouveau problème (plutôt que de mettre à jour le 1er message) car ça rend la lecture du sujet un peu complexe (les réponses ne répondant plus à la question posée). Ça permet également de suivre l'évolution du sujet (questions/réponses) et aussi ça permet d'être notifié quand tu écris un nouveau message (ce qui n'est pas le cas quand tu édites). Et puis je trouve ça un peu chiant de devoir remonter dans la file des messages .
Donc concernant ton nouveau problème, tu appelles en ligne 74 la fonction affichemot avec comme argument EntreeProp.get:
Non, ce message d'erreur veut dire qu'on ne peut pas appeler la méthode upper sur un objet qui est une fonction.
Ça veut dire que dans ton code ligne 66, la variable lettre ou la variable mot (ou les deux) est une fonction au lieu d'une chaine de caractères comme tu le pense.
Au passage ta fonction affichemot est compliquée et longue, ce serait pas mal de la découper en fonctions, et de simplifier les lignes 23 à 55 qui peuvent être réduites à 3 ou 4 lignes en utilisant un dictionnaire.
- Edité par LoupSolitaire 1 décembre 2016 à 16:47:50
Ça veut dire que dans ton code ligne 66, la variable lettre ou la variable mot (ou les deux) est une fonction au lieu d'une chaine de caractères comme tu le pense.
Tu as raison, regardes ligne 83 :
mot = trouvermot()
J'arrange comment ça du coup ?
LoupSolitaire a écrit:
Au passage ta fonction affichemot est compliquée et longue, ce serait pas mal de la découper en fonctions, et de simplifier les lignes 23 à 55 qui peuvent être réduites à 3 ou 4 lignes en utilisant un dictionnaire.
Je ne manipule pas encore super bien les dictionnaires, mais j'y penserais quand j'aurais fini ce projet et bien pris en main les dictionnaires.
Olygrim a écrit:
Reste à savoir si c'est ça que tu voulais faire?
Non, haha. Mais LoupSolitaire à compris
Mais je testerai ça plus tard et je dirais si j'obtient une erreur ou pas ?
Non, LoupSolitaire et moi disons des choses complémentaires.
Ta fonction affichemot prend deux arguments (ligne 20) qui doivent être des chaînes de caractères car tu utilises dessus la méthode upper (ligne 66 à 73) (ce que dit LoupSolitaire). Mais en ligne 74, tu utilises ta fonction avec comme argument EntreeProp.get qui est une fonction et non une chaîne de caractère (ce que je dis). Donc la solution est de mettre les parenthèses à la méthode get (ce que tu as sûrement oublier de faire) pour récupérer la valeur de l'Entry.
Le problème n'est pas ligne 83, Olygrim a bien identifié le problème.
Par contre, je l'ai peut-être déjà dit, mais il te manque des bases. Je pense pas que ce soit pertinent de jouer avec les interfaces graphiques sans avoir ces bases.
Par exemple, le fait de ne pas maîtriser les structures de données de base, que tu ne fasse pas la différence entre fonction exécutée et fonction passée en argument, que tu ne saches pas faire du debug de base avec print, et que tu ne comprenne pas bien les erreurs affichées par python.
Les deux dernières lacunes étant les plus bloquantes. Concentre toi là dessus sinon tu ne peux pas progresser.
Par exemple, le fait de ne pas maîtriser les structures de données de base, que tu ne fasse pas la différence entre fonction exécutée et fonction passée en argument, que tu ne saches pas faire du debug de base avec print, et que tu ne comprenne pas bien les erreurs affichées par python.
Pour la structure de base, je ne savais pas. Je sais bien qu'il me manque des bases, je fais de mon mieux. Le debug de base, je sais le faire mais je n'ai pas pris l'habitude. Et les erreurs, je demande seulement pour celle que je ne comprends pas et celle que je comprends. Mais que je n'arrive pas à corriger. J'ai plusieurs dizaines de programmes, j'ai eu beaucoup d'erreurs que j'ai su corriger même si c'est vrai que je poste beaucoup et souvent sur OC. Mais merci quand même pour ton conseil.
LoupSolitaire a écrit:
Le problème n'est pas ligne 83, Olygrim a bien identifié le problème.
Je pensais qu'il était là vu que je dis que mot = trouvermot(). Mais donc je dois juste rajouter les parenthèses a mon get et ce ne sera plus considéré comme une fonction ?
Mais donc je dois juste rajouter les parenthèses a mon get et ce ne sera plus considéré comme une fonction ?
Il y a deux choses à distinguer. La fonction elle-même (qui correspond à son nom) et ce que renvoie la fonction (quand on lui accole les parenthèses):
print #La fonction
print("hello") # -> None: ce que renvoie la fonction
min #la fonction
min([2, 6, 9, 1]) # -> 1: ce que renvoie la fonction
def mon_addition(x, y):
return x + y #ce qui sera récupéré lors de l'appel
mon_addition #la fonction
mon_addition(3, 4) # -> 7: ce que renvoie la fontion
Autrement dit, il y a ce qu'on appelle le callable (qui est le nom de la fonction) et il y a le ou les valeurs renvoyée(s) par la fonction (qui dépendent entièrement de la fonction elle-même). Pour récupérer ce qu'elle renvoie, il suffit d'ajouter les parenthèses et les éventuels arguments au callable.
Dans le cas d'un Entry, la méthode get permet de récupérer ce qu'à écrit l'utilisateur au format chaîne de caractère (c'est l'équivalent graphique de notre input):
my_entry.get #la méthode
my_entry.get() #ce que renvoie la méthode
Mais get est également une méthode des variables tkinter et ce qu'on récupère dépend de la classe utilisée:
v1 = tk.StringVar()
v2 = tk.IntVar()
v3 = tk.BooleanVar()
v4 = tk.DoubleVar()
#La fonction
v1.get
v2.get
v3.get
v4.get
#ce que renvoie la fonction
v1.get() # -> une chaîne
v2.get() # -> un entier
v3.get() # -> un booléen
v4.get() # -> un flottant
Parce que tu exécute affichemot avant que la fenêtre soit construite, tout simplement !
Ligne 101, tu lances l'exécution, ensuite tout se passe bien jusqu'à la ligne 74, qui exécute à nouveau la fonction, puis on arrive à la ligne 74, qui exécute encore la fonction, puis on arrive à la ligne 74...
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Blond, bouclé, toujours le sourire aux lèvres...
Blond, bouclé, toujours le sourire aux lèvres...
Blond, bouclé, toujours le sourire aux lèvres...
Blond, bouclé, toujours le sourire aux lèvres...
Blond, bouclé, toujours le sourire aux lèvres...