0
votes

Est-ce un exemple d'appel par référence, d'un bug, ou autre chose?

J'écris un petit programme pour créer une liste de permutations. J'ai lu sur le algorithme sur Wikipedia .

Mon algorithme prend essentiellement une liste initialement triée de chiffres et le permute en place. Il ajoute ensuite cette nouvelle permutation à une liste. Lorsque toutes les permutations sont trouvées, il renvoie la liste des listes contenant toutes les permutations. Il est très bon d'imprimer les résultats escomptés, mais lorsque j'essaie d'ajouter ces résultats à une liste, les choses vont un peu drôle. P>

J'ai remarqué que chaque fois que je trouve la prochaine permutation et que je l'annonce, les éléments de liste précédents sont mis à jour à la nouvelle permutation. Ainsi, à la fin de tout cela, ce qui est retourné est une liste contenant un tas de copies de la même permutation (exactement la dernière permutation). P>

J'ai lu que Python passe par valeur, passe par référence et j'ai également lu que ce n'est pas non plus. Je ne suis pas assez intelligent pour discuter avec l'une de ces personnes, mais je me demande pourquoi mon programme le fait et comment la remédier à: P>

def lexi_order(nums):

    permutations = []
    length = len(nums)


    while True:

        # find largest index i such that nums[i] < nums[i + 1]
        exists = False
        for j, elem in enumerate(nums):
            # check if last element
            if j == length - 1:
                break

            if elem < nums[j + 1]:
                i = j
                exists = True

        if not exists:
            break

        # find largest index k, such that i < k AND nums[i] < nums[k]
        for j in range(i + 1, length):
            if nums[j] > nums[i]:
                k = j

        # swap order of nums[i] and nums[k]
        nums[i], nums[k] = nums[k], nums[i]

        # reverse order of elements starting at position i+1
        to_reverse = nums[i+1:][::-1]
        nums[i+1::] = to_reverse

        permutations.append(nums)
        print(permutations)

    return permutations


5 commentaires

Vous ne copiez jamais nums - il n'y a que un seul objet que vous modifiez et ajoute à plusieurs reprises à permutations .


Python est toujours transmis par référence. Ils aident les utilisateurs à Parfois éviter les bugs liés à la référence de référence consiste à faire certains types courants immuables (int, flotteur, str, tuple). Un type immuable aide, car une fois votre variable référencée une instance d'un type immuable, vous pouvez être certain que la valeur qu'il est référencée ne changera pas. Vous devez être conscient de quels types sont et ne sont pas immuables afin d'écrire un code intelligent en Python.


@Mistermiyagi Oui, d'une manière. Il va bien avec l'une des réponses ci-dessous qui indique que je dois faire une copie pour chaque nouvelle permutation. Cependant, une pièce est manquante pour moi, qui est dans mon commentaire à cette réponse: disons que je dis temp_nums = nums , puis selon votre lien et que l'article que j'ai lu, je ne fais pas une copie. Donc, je dois apprendre à copier quelque chose au lieu de lui donner de nouveaux noms.


@HYMNSFORDISCO HMM, cela a du sens. Doit être pourquoi c'est ma première fois dans ce type de problème. Je passais par référence tout au long, mais l'immuabilité des variables que j'utilisais m'a fait penser que je faisais tout en valeur. Merci!


Calling Liste (My_List) est le moyen standard de faire une copie peu profonde d'une liste. "Copier" Quelque chose n'est pas aussi simple que vous pouvez penser. Recherchez des ressources sur la copie de VS peu profonde en Python et de copier des objets avec le module Copier


3 Réponses :


1
votes

Lorsque vous appendez nums à permutations , vous devez l'ajouter une référence à celle-ci, ne copiant pas toutes les données sur. Lorsque vous modifiez nums , il est modifié partout. Python passe par référence. Si vous modifiez une variable (à ne pas être confondu avec la réaffectation), ce changement sera reflété partout.


1 commentaires

Vous devez être vraiment prudent avec la terminologie ici, car la réaffectation d'un élément d'une liste sera réellement Changer la liste.



1
votes

Vous modifiez l'entrée ( nums ) en place chaque itération via la boucle, puis vous continuez à ajouter une référence à l'entrée à permutations . Pour le corriger, effectuez une copie de nums au début de la boucle et utilisez-le au lieu de l'original partout dans l'intérieur.


1 commentaires

Donc, j'ai lu que si je fais quelque chose comme temp_list = nums , que je donne simplement le même objet deux noms. Je lis que si je fais quelque chose à temp_list , il sera reflété dans nums aussi. Un exemple est donné ici: Jeffknupp.com / Blog / 2012/11/13 / ... . J'ai testé cela pour voir si c'était vrai et cela a fonctionné. Alors, comment puis-je faire une "copie" distincte?



1
votes

Vous devez effectuer une copie des nums code> code>, sinon vous travaillez sur la référence transmise. E.G.

def lexi_order(nums):

    permutations = []

    nums = list(nums) # We are now working on a copy, and won't mutate the original whatsoever.
    length = len(nums)
    ...


1 commentaires

Ce n'est pas suffisant. La boucle nécessite également des copies sur chaque étape d'itération.