145 votes

python pandas dataframe, est-il passer par valeur ou par référence

Si je passe un dataframe à une fonction et de le modifier à l'intérieur de la fonction, est-il passer par valeur ou par référence?

J'exécute le code suivant

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
def letgo(df):
    df = df.drop('b',axis=1)
letgo(a)

la valeur de a ne change pas après l'appel de la fonction. Signifie-t-il, il est passé par valeur?

J'ai aussi essayé la suite

xx = np.array([[1,2], [3,4]])
def letgo2(x):
    x[1,1] = 100
def letgo3(x):
    x = np.array([[3,3],[3,3]])

Il s'avère letgo2() change xx et letgo3() ne le sont pas. Pourquoi est-il comme cela?

173voto

mfripp Points 46

La réponse courte est, Python fait toujours passer par valeur, mais chaque variable Python est en fait un pointeur vers un objet, donc parfois il ressemble passé par référence.

En Python chaque objet est soit mutable ou non mutable. par exemple, les listes, les dicts, les modules et les Pandas de trames de données sont mutables, et les entiers, les chaînes et les tuples sont non-mutables. Mutable objets peuvent être modifiés en interne (par exemple, d'ajouter un élément à une liste), mais non-mutable objets ne peuvent pas.

Comme je l'ai dit au début, vous pouvez penser à chaque variable Python comme un pointeur vers un objet. Lorsque vous passer une variable à une fonction, la variable (pointeur) au sein de la fonction est toujours une copie de la variable (pointeur) qui a été passé. Si vous ajoutez quelque chose de nouveau à la variable interne, tout ce que vous faites est en train de changer la variable locale point à un autre objet. Ce n'est pas modifient (muter) l'original de l'objet que la variable pointée, ni la variable externe pointer vers le nouvel objet. À ce stade, la variable externe des points encore à l'objet d'origine, mais la variable interne pointe vers un nouvel objet.

Si vous voulez modifier l'objet original (seulement possible avec mutable types de données), vous devez faire quelque chose qui modifie l'objet , sans affectation d'une complètement nouvelle valeur à la variable locale. C'est pourquoi, letgo() et letgo3() de congé de l'élément externe inchangée, mais letgo2() il modifie.

Comme @ursan souligné, si letgo() utilisé quelque chose comme ceci au lieu de cela, il serait modifient (muter) l'original de l'objet qu' df de points à, qui allait changer la valeur perçue par le global a variable:

def letgo(df):
    df.drop('b', axis=1, inplace=True)

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
letgo(a)  # will alter a

Dans certains cas, vous pouvez complètement creux, la variable d'origine et de le remplir à nouveau avec de nouvelles données, sans vraiment faire une affectation directe, ce qui va modifier l'objet original qui v de points à, qui va changer les données visibles lorsque vous utilisez v plus tard:

def letgo3(x):
    x[:] = np.array([[3,3],[3,3]])

v = np.empty((2, 2))
letgo3(v)   # will alter v

Notez que je ne suis pas assigner quelque chose directement à l' x; je suis assigner quelque chose à l'ensemble de l'intérieur de la gamme de x.

Si vous devez absolument créer un tout nouvel objet et de le rendre visible de l'extérieur (ce qui est parfois le cas avec les pandas), vous avez deux options. Le "propre" option serait juste de retour le nouvel objet, par exemple,

def letgo(df):
    df = df.drop('b',axis=1)
    return df

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
a = letgo(a)

Une autre option serait de parvenir à l'extérieur de votre fonction et de modifier directement une variable globale. Cela change a pour pointer vers un nouvel objet, et toute fonction qui se rapporte à l' a après que les nouvelles de l'objet:

def letgo():
    global a
    a = a.drop('b',axis=1)

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
letgo()   # will alter a!

Modifier directement les variables globales est généralement une mauvaise idée, parce que toute personne qui lit votre code aura un moment difficile de déterminer combien de a a été changé. (J'en général d'utiliser des variables globales pour les paramètres partagés utilisés par de nombreuses fonctions dans un script, mais je ne leur permettez pas de modifier ces variables globales.)

15voto

ursan Points 794

Pour ajouter à @Mike Graham réponse, qui a fait une très bonne lecture:

Dans votre cas, ce qui est important à retenir est la différence entre les noms et les valeurs. a, df, xx, x, sont tous les noms, mais ils se réfèrent à la même ou de différentes valeurs à différents points de votre exemple:

  • Dans le premier exemple, letgo relie df à une autre valeur, car df.drop renvoie un nouveau DataFrame , sauf si vous définissez l'argument inplace = True (voir doc). Cela signifie que le nom de l' df (local à l' letgo de la fonction), qui se référait à la valeur de a, est maintenant en se référant à une nouvelle valeur, ici, l' df.drop de la valeur de retour. La valeur a se réfère existe toujours et n'a pas changé.

  • Dans le deuxième exemple, letgo2 mute x, sans reliaison, c'est pourquoi le xx est modifié par letgo2. Contrairement à l'exemple précédent, voici le nom local x correspond toujours à la valeur du nom de l' xx référence, et les changements de la valeur à la place, c'est pourquoi la valeur xx se réfère à la a changé.

  • Dans le troisième exemple, letgo3 relie x d'un nouveau np.array. Qui provoque le nom x, du local à l' letgo3 et précédemment en se référant à la valeur de xx, pour maintenant se référer à une autre valeur, le nouveau np.array. La valeur xx est fait référence n'a pas changé.

13voto

Mike Graham Points 22480

La question n'est pas OIP vs droits d'OBTENTEUR. Ces noms entraîner de la confusion dans un langage comme Python; qu'ils ont été inventés pour les langues qui fonctionnent comme le C ou comme Fortran (comme la quintessence de l'OIP et des droits d'OBTENTEUR langues). C'est vrai, mais pas instructif, que Python passe toujours par valeur. La question ici est de savoir si la valeur elle-même est muté ou si vous obtenez une nouvelle valeur. Les Pandas généralement trompe sur le côté de cette dernière.

http://nedbatchelder.com/text/names.html explique très bien ce que Python du système de noms de est.

7voto

dstromberg Points 3126

Python est ni le passage par valeur, ni passage par référence. Il est pass par cession.

Soutien de référence, le Python de la FAQ: https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference

OIE:

  1. Si vous passez une valeur immuable, les modifications ne changent pas les la valeur de l'appelant - parce que vous êtes à la reconsolidation du nom d'une nouvelle objet.
  2. Si vous transmettez une valeur mutable, les modifications effectuées dans la fonction appelée, aussi changer la valeur de l'appelant, tant que vous n'avez pas relier ce nom à un nouvel objet. Si vous réaffectez la variable, la création d'un nouvel objet, que les changements et les modifications ultérieures de l' le nom ne sont pas considérés en l'appelant.

Donc, si vous passez une liste, et de modifier son 0e valeur, que le changement est à la fois dans l'appelé et de l'appelant. Mais si vous réaffectez la liste avec une nouvelle liste, ce changement est perdu. Mais si vous tranche la liste et de le remplacer que par une nouvelle liste, que le changement est à la fois dans l'appelé et de l'appelant.

Par exemple:

def change_it(list_):
    # This change would be seen in the caller if we left it alone
    list_[0] = 28

    # This change is also seen in the caller, and replaces the above
    # change
    list_[:] = [1, 2]

    # This change is not seen in the caller.
    # If this were pass by reference, this change too would be seen in
    # caller.
    list_ = [3, 4]

thing = [10, 20]
change_it(thing)
# here, thing is [1, 2]

Si vous êtes un C fan, vous pouvez considérer cela comme le passage d'un pointeur en valeur pas un pointeur vers un pointeur vers une valeur, un pointeur vers une valeur.

HTH.

2voto

CodeChords man Points 3191

Voici la doc pour la chute:

Retour nouvel objet avec les étiquettes dans l'axe supprimé.

Ainsi, un nouveau dataframe est créé. L'original n'a pas changé.

Mais comme pour tous les objets en python, la trame de données est transmis à la fonction par référence.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X