2010-07-09 10 views
46

À partir de ce que je sais, les listes + op pour seulement nécessitent que le 2ème opérande soit itérable, ce qui est clairement "ha".Si x est list, pourquoi x + = "ha" fonctionne, alors que x = x + "ha" renvoie une exception?

Dans le code:

>>> x = [] 
>>> x += "ha" 
>>> x 
['h', 'a'] 
>>> x = x + "ha" 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: can only concatenate list (not "str") to list 
+1

Je suis d'accord avec votre question; c'est un bon argument contre la surcharge de l'opérateur pour moi. – u0b34a0f6ae

+0

J'ai supprimé ma réponse après votre modification - il semble que vous vous interrogiez sur la raison derrière ne pas soutenir + entre une liste et un itérable - mon erreur. A part de dire "Ouais, pourquoi pas?", Je n'ai pas de réponse. –

+3

c'est une casse * majeure *. plus généralement, tout langage ou bibliothèque qui définit des comportements différents pour des opérateurs de même apparence doit être considéré comme hostile à l'utilisateur. personne n'utiliserait '+' pour la concaténation de chaînes: cette opération n'est pas commutative! –

Répondre

33

En utilisant += une liste est comme appeler extend, pas +. Vous pouvez appeler extend avec un itérable.

  • Vous pouvez uniquement utiliser + avec une autre liste. Je ne peux que deviner pourquoi cette décision a été prise, mais j'imagine que c'est pour des raisons de performance. L'appel + entraîne la création d'un nouvel objet et la copie de tous les éléments, tandis que extend peut utiliser de l'espace libre dans l'objet de liste existant en enregistrant une copie dans certains cas.

    Un autre effet secondaire de cette décision est que si vous écrivez x += y d'autres références à la liste verront le changement, mais si vous utilisez x = x + y alors ils ne le feront pas. Ceci est démontré ci-dessous:

     
    >>> x = ['a','b'] 
    >>> y = ['c', d'] 
    >>> z = x 
    >>> x += y 
    >>> z 
    ['a', 'b', 'c', 'd'] 
    
    >>> x = ['a','b'] 
    >>> y = ['c', d'] 
    >>> z = x 
    >>> x = x + y 
    >>> z 
    ['a', 'b'] 
    

    Références

    Python source code for list.

    code source pour +=:

     
    static PyObject * 
    list_inplace_concat(PyListObject *self, PyObject *other) 
    { 
        PyObject *result; 
    
        result = listextend(self, other); 
        if (result == NULL) 
         return result; 
        Py_DECREF(result); 
        Py_INCREF(self); 
        return (PyObject *)self; 
    } 
    

    code source pour +:

     
    static PyObject * 
    list_concat(PyListObject *a, PyObject *bb) 
    { 
        Py_ssize_t size; 
        Py_ssize_t i; 
        PyObject **src, **dest; 
        PyListObject *np; 
        if (!PyList_Check(bb)) { 
         PyErr_Format(PyExc_TypeError, 
            "can only concatenate list (not \"%.200s\") to list", 
            bb->ob_type->tp_name); 
         return NULL; 
        } 
    
        // etc ... 
    
  • +20

    Je pense que la vraie question ici est, "pourquoi une telle incohérence?" – doublep

    +0

    Je suis sur le point d'aller -1 sur cette réponse car elle ne répond pas du tout à la question (voir le commentaire de @ doublep). –

    +5

    Je ne pense pas qu'il soit clair du tout que cette question soit une critique du design. La première étape doit être de comprendre comment l'incohérence est mise en œuvre, et c'est tout ce que nous pouvons aider ici. Les plus grandes questions que vous commentez sont complètement hors de la portée de SO, si vous me demandez :) –

    8

    Tu penses à l'envers. Vous demandez pourquoi x = x + 'ha' déclenche une exception, étant donné que x += 'ha' fonctionne. Vraiment, la question est pourquoi x += 'ha' fonctionne du tout.

    Tout le monde est d'accord (j'espère) que 'abc' + 'ha' et [1, 2, 3] + ['h', 'a'] devraient fonctionner. Et dans ces cas, surcharger += pour effectuer une modification sur place semble raisonnable.

    Les concepteurs de langage ont décidé que [1, 2, 3] + 'ha' ne devrait pas, parce que vous mélangez différents types. Et cela semble raisonnable aussi.

    Donc la question est pourquoi ils ont décidé de de mélanger différents types dans le cas de x += 'ha'. Dans ce cas, je suppose qu'il ya des raisons de couple:

    • Il est un raccourci pratique
    • Il est évident ce qui se passe (vous ajoutez chacun des éléments de la itérables à x)

    En général , Python essaie de vous laisser faire ce que vous voulez, mais là où il y a de l'ambiguïté, cela tend à vous forcer à être explicite.

    +2

    une autre tentative -1: pour moi, il est évident que 'x + = y' est défini comme' x = x + y' pour tout 'x' et' y'. il est immédiatement clair que vous avez évité de répondre à la question. ;) –

    +6

    Je pense que le point ici est que ce n'est * pas * évident, d'où la question. Dans la plupart des autres langages de programmation où '+ =' et '+' est défini, faire 'x + = y' est généralement défini exactement comme' x = x + y'. En fait, typiquement un est un alias pour l'autre. –

    +0

    C'est évident dans le sens où, si vous l'essayez, c'est très clair ce qui se passe. Et ce n'est pas comme si, si vous ne vous attendiez pas à ce que cela fonctionne, vous serez déçu quand cela arrivera. –

    5

    Lors de la définition des opérateurs, il existe deux opérateurs "add" différents: l'un est appelé __add__, l'autre __iadd__. Le dernier est pour les ajouts sur place avec +=, l'autre est l'opérateur + régulier. http://docs.python.org/reference/datamodel.html a plus d'infos à ce sujet.

    Questions connexes