Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problèmes dans mon programme

tatrats est tu la ? :)

    20 août 2014 à 22:01:36

    Salut les gars,

    J'ai pas mal avancé sur mon projet ( voir ici : http://fr.openclassrooms.com/forum/sujet/pygame-problemes ) mais je rencontre maintenant un, ou plutôt des, petits problèmes...

    En effet les touches peuvent contenir soit du texte, soit une image et une action est associée à leur appuis. Il y à donc, contenu dans une liste ( elle même contenu dans une liste ) un tuple par touche contenant le texte de la touche ( qui peut aussi être le chemin d'accès à une image si on veut en mettre une à la place du texte, il suffit dans ce cas de rajouter "#@" devant le texte) et l'action que doit executer cette touche.

    J'ai donc deux problèmes : Le premier est que l'image ne s'affiche bien sur une touche QUE quand aucune action n'est assigné à cette touche ( quand le tuple ne contient donc qu'un "argument" ). Sinon, est affiché en texte le chemin d'accès de l'image sur la touche.

    Mon deuxième problème est que je suis obligé d'utiliser des fonction anonymes "lambda" quand je veut associé une action à une touche. Quand j'essaye de mettre une vrais fonction j'ai une erreur :

    Traceback (most recent call last):
      File "/Users/theo/Desktop/test.py", line 419, in <module>
        kb.run()
      File "/Users/theo/Desktop/test.py", line 399, in run
        self.release(event.pos)
      File "/Users/theo/Desktop/test.py", line 353, in release
        k.run_command()
      File "/Users/theo/Desktop/test.py", line 290, in run_command
        func()
    TypeError: 'NoneType' object is not callable

    C'est donc assez embetant, surtout quand on sait qu'une fonction "lambda" ne peut contenir qu'une instruction max...

    Voila le code tel qu'il est ( Tatrats reconnaitra en grande partie son travail ) :

    # -*- coding:Utf-8 -*-
    
    ################################################################################
    #                                                                              #
    #                               Clavier2Niveaux                                #
    #         Un clavier virtuel pour utiliser un grand nombre de touches          #
    #                 sur un écran tactile de très petite taille.                  #
    #   Gère les textes à une seule ligne et toute surface pygame (image, ...).    #
    #                                                                              #
    #                          Pour python 2 ou python 3                           #
    #                                                                              #
    #                          Module tertiaire requis :                           #
    #                                    pygame                                    #
    ################################################################################
    
    import os
    import pygame
    from pygame import *
    import urllib
    import json
    import serial
    
    #bluetoothSerial = serial.Serial( "/dev/rfcomm0", baudrate=9600 )#VERSION RASPBERRY PI
    try:
    	bluetoothSerial = serial.Serial( "/dev/cu.AdafruitEZ-Link2bad-SPP", baudrate=9600 )# Initialisation bluetooth
    
    except:
    	pass	
    pygame.init()
    mixer.pre_init(frequency=44100, size=-16, channels=2, buffer=4096)
    print "Donnees d'initialisation du mixer audio :", pygame.mixer.get_init() 
    
    try:
    	RESULT=json.load(urllib.urlopen("http://www.tikimee.com/tiki-pi/json")) #Ouverture du fichier JSON
    	url_list = []
    	text_list = []
    	for elt in RESULT['result']['keys']:
    		url_list.append(elt['icon'])
    		text_list.append(elt['label'])
    		print url_list
    
    	for idx, url in enumerate(url_list):
    		image = urllib.urlopen(url) # On ouvre l'URL
    		with open('image(%d).jpg' % idx, "w+b") as output:
    			output.write(image.read())
    except:
    	pass
    # Couleurs
    C = (194,255,50)# teinte1
    def printstuff():
    	print "test"
    
    # Liste des données pour les touches du clavier
    KEYS = [
    	#couleur 
    	#| texte
    	#|   |   contenu niveau 2 (même ordre que dans la liste principale)
    	#|   |   ou tuples (contenu, fonction)
    	#|   |   (contenu : str | bytes | pygame.Surface ; une str commentéb     
    	#v   v    par "#@" désigne le chemin d'accès à une image)
    	(C, "#@image(0).jpg",["#@image(6).jpg", "#@image(9).jpg","A",
    	                      "X", ("Play", lambda: pygame.mixer.unpause()), "W"]),
    	(C, "#@image(4).jpg",[("#@image(7).jpg",lambda: bluetoothSerial.write("avancer")), "#@image(6).jpg", "#@image(12).jpg",
    	 					  ("C", printstuff()), ("Pause", lambda: pygame.mixer.pause()), "E"]),
    	(C, "#@image(1).jpg",["#@image(8).jpg","F", "#@image(6).jpg",
    	 					  "G", ("Stop", lambda: pygame.mixer.fadeout(1000)), "I"]),
    	(C, "#@image(3).jpg",["#@image(9).jpg", "J", "K",
    	 					  "#@image(6).jpg", "L", "M"]),
    	(C, "#@image(2).jpg",["#@image(10).jpg", "N", "O",
    	 					  "P", "#@image(6).jpg", "Q"]),
    	(C, "#@image(5).jpg",["#@image(11).jpg", "R", "S",
    						  "T", ("Tuto Audio", lambda: pygame.mixer.Sound('parov.wav').play()), "#@image(6).jpg"])]
    
    # Temps maximal (en ms) entre l'appui et le relâchement du clic pour que
    # celui-ci soit considéré comme un clic bref
    CLICK_DURATION = 300
    
    # Taille du clavier
    WIDTH = 320
    HEIGHT = 240
    
    # Format de la grille
    ROWS = 2
    COLUMNS = 3
    
    ################################################################################
    #                     Compatibilité python 2 pour `print`                      #
    ################################################################################
    # Attention : un seul argument est accepté par la fonction
    
    def print_func(seq):
    	print(seq)
    ################################################################################
    
    ############################ LOAD IMAGES #######################################
    def load_image(path):
    	"""Charge l'image désignée par le chemin d'accès donné
    	Renvoie None en cas d'erreur."""
    	try:
    		image = pygame.image.load(path)
    
    	except pygame.error:
    		# L'erreur pygame peut être due à des caractères spéciaux dans le
    		# chemin d'accès
    		try:
    			with open(path, "rb") as f:
    				try:
    					image = pygame.image.load(f, path).convert()
    				except pygame.error:
    					# Format d'image incorrect ou non supporté
    					image = None
    		except:
    			print "File not found" # Fichier inexistant
    			image = None
    	return image
    ###############################################################################
    ######################### DEFINITION CONTENU ##################################
    def get_content(content):
    	"""Renvoie le contenu, image ou texte, à passer au constructeur de Key()
    	"""
    	if isinstance(content, str):
    		if content[:2] == "#@":
    			image = load_image(content[2:])
    
    			if image is not None:
    				return image
    	return content
    ###############################################################################
    ######################### CREATION DES TOUCHES ################################
    def create_keys(surf):
    	"""Renvoie la liste des touches, créées à partir des données initiales
    	surf : pygame.Surface
    		surface d'affichage des touches
    	"""
    	keys_list = []
    	# Position de la case courante sur la grille
    	column = 0
    	row = 0
    	# Taille de chaque case; chaque touche fait cette taille moins deux pixels
    	# de chaque côté
    	w = 106
    	h = 120
    
    	for value, (color, content, level_2) in enumerate(KEYS):
    		rect = pygame.Rect((column * w)+2, (row * h)+1, w, h)
    		# Traitement de la liste de données des clés et transformation en
    		# dictionnaire
    
    		l_2 = {}
    		for indice, valeur in enumerate(level_2):
    			print "liste[%d] = %r" % (indice, valeur)
    
    			if isinstance(valeur, (str, bytes)):
    				l_2[indice] = (get_content(valeur), lambda t=valeur: print_func(t))
    			else:
    				l_2[indice] = get_content(valeur)
    
    		keys_list.append(Key(surf, rect.inflate(-5, -5),color, get_content(content), value, l_2))
    		print keys_list
    		column += 1
    		row += column // COLUMNS
    		column %= COLUMNS
    	return keys_list
    
    def apply_brightness(color, delta=10):
    	"""Renvoie une nouvelle couleur dont la luminosité a été changée
    	`delta` doit se situer entre -100 (plus sombre) et 100 (plus lumineux)
    	"""
    	if isinstance(color, pygame.Color):
    		new = pygame.Color(color.r, color.g, color.b, color.a)
    	elif isinstance(color, (tuple, list)):
    		new = pygame.Color(*color)
    	else:
    		new = pygame.Color(color)
    	h, s, l, a = new.hsla
    	new.hsla = (h, s, max(min(int(l + delta), 100), 0), a)
    	return new
    
    class Key(object):
    	"""Objet représentant une touche du clavier virtuel"""
    	def __init__(self, surf, rect, color, content, value, level_2={}):
    		"""Constructeur de l'objet Key()
    		surf : pygame.Surface
    			surface où dessiner la touche
    		rect : pygame.Rect
    			rectangle délimitant la touche
    		color : pygame.Color
    			couleur propre de la touche
    		content : str | bytes | pygame.Surface
    			texte (str | bytes) ou image, affiché sur la touche au niveau 1
    		value : object
    			valeur de la touche, utilisée dans le second niveau
    			Chaque touche du clavier doit avoir une valeur différente.
    		level_2={} : {object: [(str | bytes | pygame.Surface), callable]}
    			données de la touche pour le niveau 2
    			Chaque clé du dictionnaire correspond à la valeur de la touche
    			cliquée au niveau 1; lui est associé une liste contenant le texte
    			ou image qui sera affichée sur la touche et la fonction à appeler
    			si le clic est relâché sur la touche courante."""
    		self.surf = surf
    		self.rect = rect
    		self.color = color
    		self.value = value
    
    		# Si le contenu est un texte, on l'écrit immédiatement sur une surface
    		if isinstance(content, (str, bytes)):
    			self.content = FONT.render(content, True, (0, 0, 0))
    		else:
    			self.content = content
    		# On opère de même pour le niveau 2
    		for key, (cont, func) in level_2.items():
    			if isinstance(cont, (str, bytes)):
    				level_2[key] = [FONT.render(cont, True, (0, 0, 0)), func]
    		self.level_2 = level_2
    		# Rectangle d'origine de la touche
    		self._rect = rect
    		# Si une touche niveau 1 est enfoncée, la touche enfoncée sera assignée
    		# à l'attribut suivant, qui permet de savoir la couleur et la valeur
    		# de la touche enfoncée.
    		# Si aucune touche n'est enfoncée, l'attribut revient à None.
    		self.down = None
    		# Présence de la souris au-dessus de la touche
    		self.has_focus = False
    
    	def __bool__(self):
    		"""Renvoie le booléen caractérisant la touche; ce sera toujours `True`"""
    		return True
    
    	def draw(self):
    		"""Redessine la touche en prenant en compte l'éventuelle touche enfoncée
    		La fonction n'appelle pas pygame.display.flip()"""
    		if not self.down:
    			color = self.color
    			content = self.content
    		else:
    			color = self.down.color
    			value = self.down.value
    			if value in self.level_2.keys():
    				content = self.level_2[value][0]
    			else:
    				content = None
    		rect = self.rect
    		if self.has_focus:
    			color = apply_brightness(color, 20)
    
    		# On colore la touche
    		self.surf.fill(color, rect)
    		# On "blitte" le contenu de la touche
    		self.surf.blit(content, content.get_rect(center=self.rect.center))
    
    	def set_level_2(self, key):
    		"""Met la touche au niveau 2 lorsqu'une touche a été cliquée
    		key : Key
    			touche cliquée au niveau 1"""
    		self.down = key
    		if key is self:
    			self.rect = self._rect.inflate(0, 0).clamp(self.surf.get_rect())
    		else:
    			self.rect = self._rect
    		self.draw()
    
    	def end_level_2(self):
    		"""Ramène la touche au niveau 1"""
    		self.down = False
    		self.rect = self._rect
    		self.draw()
    
    	def set_focus(self):
    		"""Indique que la souris est sur la touche, et la met en surbrillance
    		Renvoie True si l'écran doit être rafraîchi"""
    		if not self.has_focus:
    			self.has_focus = True
    			return True
    		else:
    			return False
    
    	def release_focus(self):
    		"""Indique que la souris n'est plus sur la touche
    		Renvoie True si l'écran doit être rafraîchi"""
    		if self.has_focus:
    			self.has_focus = False
    			return True
    		else:
    			return False
    
    	def run_command(self):
    		"""Lance la fonction associée à la touche de niveau 2"""
    		if self.down.value in self.level_2.keys():
    			func = self.level_2[self.down.value][1]
    			func()
    
    class Keyboard(object):
    	"""Objet représentant le clavier virtuel ; il est composé de plusieurs Key()"""
    	def __init__(self, surf, keys):
    		"""Constructeur de l'objet Keyboard()
    		surf : pygame.Surface
    			surface d'affichage du clavier
    		keys : [Key, ...]
    			liste des touches du clavier"""
    		self.surf = surf
    		self.keys = keys
    		# Touche de niveau 1 pressée
    		self.pressed = None
    		# Temps de début du clic
    		self.click_time = 0
    		self.keep_level_2 = False
    		self.draw()
    
    	def click(self, coord):
    		"""Fonction appelée lorsqu'on clique sur le clavier
    		coord : (int, int)
    			coordonnées du clic"""
    		self.click_time = pygame.time.get_ticks()
    		if not self.keep_level_2:
    			# Recherche du bouton cliqué
    			for k in self.keys:
    				if k.rect.collidepoint(coord):
    					self.pressed = k
    					# Passage de toutes les touches au niveau 2
    					for kk in self.keys:
    						kk.set_level_2(k)
    					break
    		self.draw()
    
    	def release(self, coord):
    		"""Fonction appelée lorsque le clic est relâché
    		coord : (int, int)
    			coordonnées du relâchement"""
    		for k in self.keys:
    			# Recherche de la touche où a lieu le relâchement
    			if k.rect.collidepoint(coord):
    				# Appui et relâchement ont eu lieu sur la même touche
    				if k is self.pressed:
    					if pygame.time.get_ticks()-self.click_time > CLICK_DURATION:
    						# Le clic n'est pas bref, on l'ignore
    						break
    
    					# Basculement entre sous-menu toujours ouvert et sous-menu
    					# fermé
    					if self.keep_level_2:
    						# S'il était ouvert
    						self.pressed = None
    						for kk in self.keys:
    							kk.end_level_2()
    
    					# On bascule
    					self.keep_level_2 = not self.keep_level_2
    					self.draw()
    					return
    
    				# Exécution de l'action rattachée à la touche
    				else:
    					k.run_command()
    				break
    
    		if not self.keep_level_2:
    			# Passage de toutes les touches au niveau 1
    			for kk in self.keys:
    				kk.end_level_2()
    			self.pressed = None
    		self.draw()
    
    	def draw(self):
    		"""Redessine le clavier"""
    		self.surf.fill((150, 150, 150))
    
    		for k in self.keys:
    			if k is not self.pressed:
    				k.draw()
    
    		# On dessine en dernier l'éventuelle touche pressée
    		if isinstance(self.pressed, Key):
    			self.pressed.draw()
    
    		pygame.display.flip()
    
    	def update_focus(self, coord):
    		"""Met en surbrillance la touche sous le curseur
    		coord : (int, int) position du curseur"""
    		# Indique si l'écran doit être redessiné
    		refresh = False
    		for k in self.keys:
    			if k.rect.collidepoint(coord):
    				refresh |= k.set_focus()
    			else:
    				refresh |= k.release_focus()
    		if refresh:
    			self.draw()
    
    	def run(self):
    		"""Lance la boucle principale pour gérer les événements"""
    		while True:
    			event = pygame.event.wait()
    			if event.type == MOUSEBUTTONDOWN and event.button == 1:
    				self.click(event.pos)
    
    			elif event.type == MOUSEBUTTONUP and event.button == 1 and\
    					self.pressed:
    				self.release(event.pos)
    
    			if event.type == MOUSEMOTION:
    				self.update_focus(event.pos)
    
    			elif event.type == QUIT:
    				a = range(0, elt)
    				for i in a:
    					os.remove(image(a).jpg)
    				pygame.display.quit()
    				exit(0)
    
    
    if __name__ == '__main__':
    	
    	FONT = pygame.font.SysFont("Times", 14, True)
    	screen = pygame.display.set_mode((WIDTH, HEIGHT))
    	pygame.display.set_caption("Clavier virtuel")
    	keys = create_keys(screen)
    	kb = Keyboard(screen, keys)
    	kb.run()



    • Partager sur Facebook
    • Partager sur Twitter
    Perl – The only language that looks the same before and after RSA encryption.
      21 août 2014 à 10:34:26

      J'ai fais pas mal de tests ce matin et j'ai réussi à résoudre mon deuxième problème. En fait, il suffisait de lancer ma fonction associé depuis une fonction lambda comme ca : lambda: printstuff(). Ce n'est peut être pas la meilleurs facon de faire mais ca marche donc ca me va ;)

      En revanche, je n'est toujours pas résolu mon premier problème et en appelle donc encore à votre aide :)

      • Partager sur Facebook
      • Partager sur Twitter
      Perl – The only language that looks the same before and after RSA encryption.
        21 août 2014 à 23:45:52

         Tiens, te revoilà...

         Commençons par le problème numéro 2 (j'aime ma logique) : quand tu associes une vraie fonction à ta touche, tu ne dois pas mettre dans les options :

        ("texte de la touche", fonction())


        Mais:

        ("texte de la touche", fonction)

        sans les parenthèses.

        Petite explication: quand tu mets les parenthèses, python exécute la fonction dès qu'il exécute la ligne. En l'occurrence, il exécute printstuff() dès qu'il lit la ligne des options. Et il met dans le tuple la valeur renvoyée par la fonction (None). Du coup, quand tu veux exécuter la fonction, ce que tu fais correspond à : None() . Normal qu'il ne soit pas content. Le seul cas où il n'éxécute pas "fonction()" lorsqu'il lit la ligne, c'est quand tu mets cette fonction dans une lambda. Dans ce cas, la fonction sera bien exécutée lors de l'appel de la fonction lambda, comme tu le veux (et comme tu l'as remarqué).

        Mais il y a plus simple. Si tu écris le nom de la fonction sans les parenthèses, il n'exécute pas la fonction et met sa référence (son adresse mémoire, en gros) dans le tuple. Et ça marche.

        Edit: par contre, l'utilisation d'une lambda est nécéssaire si tu veux "enregistrer" des argument pour la fonction, par exemple pour `print` (je parle de la fonction print de python 3):

        contenu = ("écrire", lambda: print("texte"))

        L'explication en code : 

        # code
        def func():
            print("fonction exécutée")
            return "valeur de retour"
        
        print("test 1")
        contenu = ("texte", func())
        print(contenu[1])
        print(contenu[1]())
        
        print("\ntest 2")
        contenu = ("texte", lambda: func())
        print(contenu[1])
        print(contenu[1]())
        
        print("\ntest 3")
        contenu = ("texte", func)
        print(contenu[1])
        print(contenu[1]())
        
        # Résultat à l'exécution:
        
        test 1
        fonction exécutée
        valeur de retour
        TypeError: type str is not callable
        
        test 2
        <function lambda at 0x...>
        fonction exécutée
        valeur de retour
        
        test 3
        <function func at 0x...>
        fonction exécutée
        valeur de retour
        


        La solution du problème numéro 1 devrait arriver bientôt.


        -
        Edité par tatrats 21 août 2014 à 23:52:21

        • Partager sur Facebook
        • Partager sur Twitter
          22 août 2014 à 0:04:16

          Bon, pour le problème 1, mea culpa. Quand on ne teste son code qu'à moitié, on le refile au premier venu, encore truffé d'erreurs. Je n'aurais pas dû écrire (dans `create_keys`):

          else:
              l_2[indice] = get_content(valeur)

          mais plutôt:

          else:
              l_2[indice] = (get_content(valeur[0]), valeur[1])

          Je pense que tu peux comprendre tout seul pourquoi ça ne faisait absolument rien.

          Edit: tiens, je n'avais pas remarqué la petite dédicace dans le sous-titre du sujet !

          -
          Edité par tatrats 22 août 2014 à 0:07:14

          • Partager sur Facebook
          • Partager sur Twitter
            22 août 2014 à 14:02:21

            Si je puis me permettre quelques remarques:

            Remarque 1

            évite from pygame import * : la syntaxe import * est déconseillée sauf dans certains cas précis. En effet, mieux vaut importer chaque module pygame séparément si quelques uns seulement sont requis from pygame import display, mixer ou carrément importer le module entier : import pygame. Il y a à cela une raison : tu ne sais pas quels noms sont importés. Du coup, tu peux avoir des conflits de noms, et d'autre part, quelqu'un qui lit ton code (ou toi dans un mois ou deux) ne saura pas à quoi correspond image, alors qu'on sait tout de suite qu'il s'agit d'un module pygame en écrivant:

            from pygame import image
            image.open(...
            

            ou:

            import pygame
            pygame.image.open(...
            

            Par contre, l'utilisation du joker est justifiée dans certains cas:

            • dans les programmes mathématiques: from math import *
            • pour importer toutes les constantes pygame mais rien d'autre: from pygame.locals import *
            • et quelques autres utilisations

            Remarque 2

            Tu aurais (je pense) plutôt avantage à faire un code compatible python 3, même s'il est principalement destiné à python 2. Ce n'est pas très compliqué vu que python est rétro-compatible sauf pour print: la seule chose que tu as à faire pour que ce soit compatible python 3 est de rajouter les parenthèses pour les arguments du print, ou mieux, d'utiliser print_func() lorsque tu veux écrire quelque chose.

            Remarque 3

            C'est une remarque personnelle, mais elle me semble justifiée: évite de mettre trop de code au niveau global : tu devrais mettre ta gestion du bluetooth et du json dans une fonction ou dans le if __name__ == "__main__" (et si c'est une fonction l'appeler dans cette dernière partie). Comme ça, si un autre programme doit utiliser une classe de celui-là, il peut l'importer sans déclencher lamise en route du bluetooth et la recherche de la config.

            Remarque 4

            À bannir absolument:

            try:
                ...
            except:
                ...
            

            Tu dois toujours mettre une exception après except : sinon, tu ne pourras pas arrêter ton programme avec Ctrl+C ; si d'autre part des erreurs non prévues surviennent, tu ne sauras pas lesquelles et tu ne pourras rien déboguer. Si tu ne sais pas quelles erreurs peuvent survenir et que tu te fiches de savoir laquelle a été levée, écris except Exception qui regroupe toutes les erreurs mais pas les signaux (notamment le signal d'arrêt).

            • Partager sur Facebook
            • Partager sur Twitter
            Anonyme
              22 août 2014 à 15:11:40

              Juste deux petites choses :

              Python3 n'est pas rétro-compatible avec Python2. C'est important, la fonction print n'est pas le seul changement, il y en a d'autres beaucoup plus subtiles tel que la distinction claire et précise entre chaîne de caractères (type str full-unicode) et chaîne de bytes (type bytes).

              from math import * écrase la built-in pow(...) qui correspond à l’algorithme d'exponentiation rapide et modulaire par la fonction math.pow qui n'est ni modulaire ni rapide... :-°

              Utiliser le joker pour importer les constantes est une pratique répandu, mais je ne suis pas sûr que ce soit réellement justifiable.

              Pour tout le reste, je suis assez d'accord. ;)

              • Partager sur Facebook
              • Partager sur Twitter
              Anonyme
                22 août 2014 à 15:23:05

                @psycopy,

                En général c'est très peu conseillé en effet d'utiliser from module import *, cependant si la documentation officielle s'y met, pas étonnant de la suivre dans son sens, non?

                As a convenience, most of the top-level variables in pygame have been placed inside a module named ‘pygame.locals’. This is meant to be used with ‘from pygame.locals import *’, in addition to ‘import pygame’.

                -
                Edité par Anonyme 22 août 2014 à 15:24:36

                • Partager sur Facebook
                • Partager sur Twitter
                Anonyme
                  22 août 2014 à 15:45:48

                  Pour les constantes, ça se fait très souvent. tkinter fait la même chose, mais ça peut se comprendre si le module que l'on développe est un nouveau widget par exemple. Le fait d'importer les constantes de tkinter directement dans le nouveau module a un coté pratique pour l'utilisateur final qui n'aura alors besoin de n'importer que le nouveau module, et pourquoi pas, si c'est le seul, il pourra aussi l'importer avec le joker.

                  En fait, on déconseille le joker quand on ne sait pas ce que l'on fait, mais si on est certain que ça n'écrasera aucun nom globale ou local ou que l'écrasement est volontaire, alors il n'y a pas de problème à utiliser le joker (il existe justement pour simplifier la vie au gens qui savent ce qu'ils font) ;)

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Anonyme
                    22 août 2014 à 16:03:37

                    L'espace de noms est assez imposant sur Tkinter, si on utilise des variables et l'anglais, ça risque de faire mal, c'est assez incertains. On le fait très souvent pour démontrer par des petits codes des fonctionnalités, mais je n'utilise jamais from tkinter import *
                    mais plutôt import tkinter as tk afin d'éviter justement les collisions entre mes variables et l'espace de noms du module.

                    La PEP8 d'ailleurs défend cette importation que dans un cas particulier

                    There is one defensible use case for a wildcard import, which is to republish an internal interface as part of a public API (for example, overwriting a pure Python implementation of an interface with the definitions from an optional accelerator module and exactly which definitions will be overwritten isn't known in advance)

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Anonyme
                      22 août 2014 à 16:44:20

                      Je parles bien entendu des modules de constantes tel que pygame.locals ou tkinter.constants qui sont conçu pour être importés entièrement dans un espace de nom quelconque. Ils sont fait pour ça, et donc ne poseront, dans la grande majorité des cas, aucun problème.

                      La pep parle d'un cas défendable, mais ne dit pas que c'est le seul. Comme je le disais, la question est surtout de savoir ce que l'on fait.

                      • Partager sur Facebook
                      • Partager sur Twitter
                      Anonyme
                        22 août 2014 à 17:00:47

                        Il est inutile d'importer tkinter.constants, il est automatiquement importé avec import tkinter ... ;)

                        -
                        Edité par Anonyme 22 août 2014 à 17:01:21

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Anonyme
                          22 août 2014 à 17:25:20

                          Et bien justement, la différence est là. Quand on importe tkinter comme ça from tkinter import * on importe tout les noms contenu dans .../tkinter/__init__.py dont un tas de fonctions et de classes portant des noms qui peuvent poser problème. Alors qu'avec l'import from tkinter.constants import * on importe uniquement les constantes commune à tout le package tkinter.

                          >>> import tkinter
                          >>> dir(tkinter)
                          ['ACTIVE', 'ALL', 'ANCHOR', 'ARC', 'BASELINE', 'BEVEL', 'BOTH', 'BOTTOM', 'BROWSE', 'BUTT', 'BaseWidget', 'BitmapImage', 'BooleanVar', 'Button', 'CASCADE', 'CENTER', 'CHAR', 'CHECKBUTTON', 'CHORD', 'COMMAND', 'CURRENT', 'CallWrapper', 'Canvas', 'Checkbutton', 'DISABLED', 'DOTBOX', 'DoubleVar', 'E', 'END', 'EW', 'EXCEPTION', 'EXTENDED', 'Entry', 'Event', 'FALSE', 'FIRST', 'FLAT', 'Frame', 'GROOVE', 'Grid', 'HIDDEN', 'HORIZONTAL', 'INSERT', 'INSIDE', 'Image', 'IntVar', 'LAST', 'LEFT', 'Label', 'LabelFrame', 'Listbox', 'MITER', 'MOVETO', 'MULTIPLE', 'Menu', 'Menubutton', 'Message', 'Misc', 'N', 'NE', 'NO', 'NONE', 'NORMAL', 'NS', 'NSEW', 'NUMERIC', 'NW', 'NoDefaultRoot', 'OFF', 'ON', 'OUTSIDE', 'OptionMenu', 'PAGES', 'PIESLICE', 'PROJECTING', 'Pack', 'PanedWindow', 'PhotoImage', 'Place', 'RADIOBUTTON', 'RAISED', 'READABLE', 'RIDGE', 'RIGHT', 'ROUND', 'Radiobutton', 'S', 'SCROLL', 'SE', 'SEL', 'SEL_FIRST', 'SEL_LAST', 'SEPARATOR', 'SINGLE', 'SOLID', 'SUNKEN', 'SW', 'Scale', 'Scrollbar', 'Spinbox', 'StringVar', 'Studbutton', 'TOP', 'TRUE', 'Tcl', 'TclError', 'TclVersion', 'Text', 'Tk', 'TkVersion', 'Toplevel', 'Tributton', 'UNDERLINE', 'UNITS', 'VERTICAL', 'Variable', 'W', 'WORD', 'WRITABLE', 'Widget', 'Wm', 'X', 'XView', 'Y', 'YES', 'YView', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '_cnfmerge', '_default_root', '_exit', '_fix', '_flatten', '_join', '_magic_re', '_setit', '_space_re', '_stringify', '_support_default_root', '_test', '_tkerror', '_tkinter', '_varnum', 'colorchooser', 'commondialog', 'constants', 'dialog', 'filedialog', 'font', 'getboolean', 'getdouble', 'getint', 'image_names', 'image_types', 'mainloop', 'messagebox', 're', 'simpledialog', 'sys', 'wantobjects']
                          >>> dir(tkinter.constants)
                          ['ACTIVE', 'ALL', 'ANCHOR', 'ARC', 'BASELINE', 'BEVEL', 'BOTH', 'BOTTOM', 'BROWSE', 'BUTT', 'CASCADE', 'CENTER', 'CHAR', 'CHECKBUTTON', 'CHORD', 'COMMAND', 'CURRENT', 'DISABLED', 'DOTBOX', 'E', 'END', 'EW', 'EXTENDED', 'FALSE', 'FIRST', 'FLAT', 'GROOVE', 'HIDDEN', 'HORIZONTAL', 'INSERT', 'INSIDE', 'LAST', 'LEFT', 'MITER', 'MOVETO', 'MULTIPLE', 'N', 'NE', 'NO', 'NONE', 'NORMAL', 'NS', 'NSEW', 'NUMERIC', 'NW', 'OFF', 'ON', 'OUTSIDE', 'PAGES', 'PIESLICE', 'PROJECTING', 'RADIOBUTTON', 'RAISED', 'RIDGE', 'RIGHT', 'ROUND', 'S', 'SCROLL', 'SE', 'SEL', 'SEL_FIRST', 'SEL_LAST', 'SEPARATOR', 'SINGLE', 'SOLID', 'SUNKEN', 'SW', 'TOP', 'TRUE', 'UNDERLINE', 'UNITS', 'VERTICAL', 'W', 'WORD', 'X', 'Y', 'YES', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
                          
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Anonyme
                            22 août 2014 à 17:58:43

                            Oui mais pourquoi importer juste les constantes, on importe forcément tkinter pour ses widgets, il n'y a donc plus d'intérêt à importer ses constantes, elles le seront déjà lors du 1er import.

                            Je sais pas si tu vois où je veux en venir

                            • Partager sur Facebook
                            • Partager sur Twitter
                            Anonyme
                              22 août 2014 à 18:51:10

                              L'idée c'est de n'importer que ce dont on, ou l'utilisateur du module, a besoin et de ne pas encombrer l'espace de noms. À part ça, ça ne change rien, effectivement.

                              • Partager sur Facebook
                              • Partager sur Twitter

                              Problèmes dans mon programme

                              × 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.
                              • Editeur
                              • Markdown