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?

je lance 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 a ne change pas après l'appel de la fonction. Signifie-t-il, il est passé par valeur?

j'ai aussi essayé le suivant

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() n'est pas. Pourquoi est-il comme cela?

31
demandé sur nos 2016-08-11 14:59:13

6 réponses

La réponse est courte, 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 cadres de données lists, dicts, modules et Pandas sont mutables, et les ints, strings et tuples sont non-mutables. Les objets mutables peuvent être modifiés en interne (par exemple, ajouter un élément à une liste), mais pas les objets non mutables.

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é. Donc si vous assignez quelque chose de nouveau à la variable interne, tout ce que vous faites est de changer la variable locale pour pointer vers un objet différent. Cela ne modifie pas (mute) l'objet original que la variable pointait, ni ne fait la variable externe pointer vers le nouveau objet. À ce point, la variable externe pointe toujours vers l'objet original, mais la variable interne pointe vers un nouvel objet.

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

comme @ursan l'a fait remarquer hors, si letgo() utilisé quelque chose comme ceci à la place, puis il modifierait (muter) l'objet original qui df points to, ce qui changerait la valeur Vue via le global a la 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 vider la variable d'origine et la remplir avec de nouvelles données, sans faire réellement une affectation directe, par exemple cela va modifier l'objet d'origine qui v 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 n'attribue pas directement quelque chose à x; je suis assigner quelque chose à l'ensemble de l'intérieur de la gamme de x.

si vous devez absolument créer un objet complètement nouveau et le rendre visible extérieurement (ce qui est parfois le cas avec pandas), vous avez deux options. L'option' clean ' serait simplement de retourner 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 d'aller à l'extérieur de votre fonction et directement modifier une variable globale. Cela change a pour pointer vers un nouvel objet, et toute fonction qui se rapporte à a ensuite va voir ce nouvel 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 habituellement une mauvaise idée, parce que quiconque lit votre code aura du mal à comprendre comment