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.)