2
votes

Classe personnalisée utilisant le dictionnaire imbriqué Python

J'ai un problème lors de l'ajout de valeur dans le dictionnaire imbriqué en utilisant les mêmes clés et la valeur est toujours affichée avec la même valeur, le fait est que je veux mettre à jour l'événement de valeur, les clés sont les mêmes. Cet algorithme est la base de l'algorithme Artificial Fish Swarm

# example >> fish_template = {0:{'weight':3.1,'visual':2,'step':1},1:'weight':3,'visual':4,'step':2}}

fish = {}
fish_value = {}
weight = [3.1, 3, 4.1, 10]
visual = [2, 4, 10, 3]
step = [1, 2, 5, 1.5]

len_fish = 4

for i in range(0,len_fish):
  for w, v, s in zip(weight, visual, step):
     fish_value["weight"] = w
     fish_value["visual"] = v
     fish_value["step"] = s
     fish[i] = fish_value

  print("show fish",fish)

Je m'attends à ce que le résultat soit comme fish_template, mais ce n'est pas le cas. Les valeurs des clés 'weight', 'visual', 'step' sont toujours les mêmes avec des valeurs de 0, 1, 2 et 3. Une solution?


2 commentaires

Parce que l'aliasing; la ligne fish [i] = fish_value est une mauvaise pratique, fish_value est écrasée. Mais vraiment, vous pouvez éviter la boucle avec une compréhension de dict. Quoi qu'il en soit, une meilleure pratique de codage consiste à déclarer votre propre classe Fish avec des membres weight, visual, step.


@smci, d'accord, il vaut donc mieux créer une classe ou un objet pour saisir la valeur de chaque boucle, merci pour vos conseils


3 Réponses :


1
votes

Je ne suis pas sûr de bien comprendre ce que vous essayez de faire ici, mais le problème est la dernière ligne de votre boucle for intérieure. Vous faites une boucle sur i dans la boucle principale, puis la boucle interne définit fish [i] plusieurs fois. En conséquence, toutes vos fish_value seront identiques.


1 commentaires

oui, j'ai déjà essayé d'imprimer à l'intérieur, la valeur est affichée, mais quand j'obtiens de la dernière boucle, la dernière valeur n'est pas toute la valeur après l'ajout



3
votes

Le problème est avec fish [i] , vous avez simplement créé un dict avec le même élément: fish_value . Python ne génère pas de nouvelle mémoire pour le même nom de variable, donc toutes vos clés dict pointent vers la même valeur = fish_value , qui est écrasée et toutes vos valeurs dict prennent le dernier état de fish_value . Pour surmonter cela, vous pouvez faire ce qui suit:

fish = dict((i, {"weight": weight[i], "visual": visual[i], "step": step[i]}) for i in range(len_fish))

Comme @Error l'a mentionné, la boucle for peut être remplacée par cette one-liner:

fish   = {}
weight = [3.1, 3, 4.1, 10]
visual = [2, 4, 10, 3]
step   = [1, 2, 5, 1.5]

len_fish = 4

for i in range(0, len_fish):
     fish[i]= {"weight": weight[i], "visual": visual[i], "step": step[i]}

print("show fish", fish)


2 commentaires

Vous pourriez une ligne ceci avec la compréhension du dictionnaire.


@ Error-SyntacticalRemorse: Je montre la compréhension d'une ligne ci-dessous. Utiliser une classe personnalisée, mais ce n'est pas nécessaire.



1
votes

En raison de aliasing ; la ligne fish [i] = fish_value est une mauvaise pratique, fish_value est écrasée à chaque fois que vous bouclez; alors fish [i] = fish_value attribue simplement une copie peu profonde dans fish [i] , ce qui n'est pas ce que vous voulez. Mais vraiment, vous pouvez éviter la boucle avec une compréhension de dict .

Quoi qu'il en soit, une meilleure pratique de codage consiste à déclarer votre propre classe Fish avec le poids des membres , visuel, étape , comme ci-dessous. Notez comment:

  • nous utilisons la fonction zip () pour combiner les listes w, v, s séparées en un tuple de liste.
  • Ensuite, la syntaxe * wvs décompresse chaque tuple en trois valeurs distinctes ('weight', 'visual', 'step'). Cela s'appelle décompression de tuple , cela vous évite d'avoir besoin d'une autre boucle, ou indexation.
  • une méthode __repr __ () personnalisée (avec art ASCII facultatif) rend chaque objet lisible par l'utilisateur. (Strictement, nous devrions remplacer __str__ plutôt que __repr__ , mais cela fonctionne)

Code:

class Fish():
    def __init__(self, weight=None, visual=None, step=None):
        self.weight = weight
        self.visual = visual
        self.step = step
    def __repr__(self):
        """Custom fishy __repr__ method, with ASCII picture"""
        return f'<º)))< 🐟 [ Weight: {self.weight}, visual: {self.visual}, step: {self.step} ]'
    # define whatever other methods you need on 'Fish' object...

# Now create several Fish'es...
swarm = [ Fish(*wvs) for wvs in zip([3.1, 3, 4.1, 10], [2, 4, 10, 3], [1, 2, 5, 1.5]) ]
# zip() function combines the lists into a tuple-of-list. `*wvs` unpacks each tuple into three separate values ('weight', 'visual', 'step')

# See what we created...
>>> swarm
[<º)))< 🐟 [ Weight: 3.1, visual: 2, step: 1 ], <º)))< 🐟 [ Weight: 3, visual: 4, step: 2 ], <º)))< 🐟 [ Weight: 4.1, visual: 10, step: 5 ], <º)))< 🐟 [ Weight: 10, visual: 3, step: 1.5 ]]

# ... or for prettier output...
>>> for f in swarm: print(f)

<º)))< 🐟 [ Weight: 3.1, visual: 2, step: 1 ]
<º)))< 🐟 [ Weight: 3, visual: 4, step: 2 ]
<º)))< 🐟 [ Weight: 4.1, visual: 10, step: 5 ]
<º)))< 🐟 [ Weight: 10, visual: 3, step: 1.5 ]


4 commentaires

Les classes doivent strictement remplacer leur __str__ plutôt que __repr__ , mais cela fonctionne à moins que vous ne souhaitiez pickle votre Fish .. . ;-)


Chose sûre. Lorsque vous accédez à 15 réputation, vous pouvez voter pour les réponses que vous avez trouvées utiles . Jusque-là, joyeux essaim ...


Avez-vous aimé la méthode personnalisée Fishy __repr__ ?


J'ai déjà créé mon propre poisson personnalisé basé sur la première réponse avant votre réponse. Désolé, mais votre réponse me donne un autre aperçu du nouveau code, merci