ProgrammationDéveloppeur Backend

Qu'est-ce que le passage d'arguments par référence et par valeur en Python ? Comment Python met-il en œuvre ce mécanisme et pourquoi est-il important de les distinguer lors de la conception de fonctions ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Comprendre comment Python passe des arguments aux fonctions est crucial pour éviter des modifications inattendues des données et pour concevoir du code correctement.

Contexte

Dans les langages de programmation traditionnels, tels que C ou Java, le passage par valeur (copy by value) ou par référence (copy by reference) est utilisé. Cependant, Python adopte un modèle différent : appel par référence d'objet (parfois appelé "appel par partage").

Problème

De nombreux développeurs pensent à tort que Python passe toujours des arguments par référence ou par valeur. Cela conduit inévitablement à des situations où des objets modifiables sont modifiés de manière inattendue dans le code appelant.

Solution

En Python, les valeurs des paramètres de fonction sont des références aux objets qui sont passés à la fonction. Cela signifie :

  • Si l'objet est modifiable (mutable : list, dict, set…) — il peut être modifié à l'intérieur de la fonction, et cela sera reflété à l'extérieur.
  • Si l'objet est immutable (immutable : int, str, tuple, frozenset), essayer de le modifier à l'intérieur de la fonction entraînera la création d'un nouvel objet et ne touchera pas à l'extérieur.

Exemple :

# list - modifiable (mutable) def add_item(lst): lst.append(42) my_list = [1, 2, 3] add_item(my_list) print(my_list) # [1, 2, 3, 42] # int - immuable (immutable) def add_num(x): x = x + 1 num = 10 add_num(num) print(num) # 10

Caractéristiques clés :

  • Les objets modifiables peuvent être modifiés à l'intérieur de la fonction — ces modifications sont visibles à l'extérieur.
  • Les objets immuables ne sont pas affectés par la fonction — seuls de nouveaux objets sont créés.
  • Python ne copie jamais automatiquement les arguments, même des structures modifiables sont toujours passées "par référence".

Questions pièges.

Les arguments sont-ils toujours passés par référence en Python ?

Non, en Python, ce sont des références aux objets qui sont passées, et le comportement de l'objet dépend de sa nature, modifiable ou non. Un objet immuable créera un nouvel objet en cas de modification.

Peut-on réaffecter un argument modifiable dans une fonction et affecter l'objet externe ?

Non. Si vous réaffectez une nouvelle valeur au paramètre à l'intérieur de la fonction, l'objet externe ne changera pas — vous ne faites que changer la référence locale.

Exemple :

def reassign_list(lst): lst = [99, 100] my_list = [1, 2, 3] reassign_list(my_list) print(my_list) # [1, 2, 3]

Pourquoi une fonction qui prend une liste par défaut peut-elle se comporter de manière étrange lors d'appels répétés ?

Parce que la valeur par défaut est créée une fois — lors de la définition de la fonction, et si elle est modifiée (par exemple, en ajoutant un élément), elle changera pour tous les appels suivants.

def add_element(x, cache=[]): cache.append(x) return cache print(add_element(1)) # [1] print(add_element(2)) # [1, 2]

Erreurs typiques et anti-modèles

  • Utilisation d'arguments modifiables par défaut (comme dans le dernier exemple).
  • Attendre que la fonction ne modifie pas la liste ou le dict passé, même si elle les modifie.
  • Confondre les effets des fonctions lors du travail avec des objets modifiables et immuables.

Exemple de la vie

Cas négatif

Un programmeur passe une liste à une fonction et s'attend à ce que sa liste d'origine ne change pas, mais la fonction ajoute un élément.

Avantages :

  • Exécution rapide, pas de copie de données.

Inconvénients :

  • Effets secondaires inattendus, bugs dans un grand code si quelqu'un ne sait pas que l'argument a été modifié.

Cas positif

Un programmeur copie explicitement la liste à l'intérieur de la fonction, s'il a besoin de renvoyer quelque chose, mais de ne pas modifier l'original :

def process_data(data): data = data.copy() # ou list(data) # travail sécurisé avec la copie data.append('rapport') return data

Avantages :

  • Pas d'effets secondaires indésirables, original protégé.

Inconvénients :

  • Lorsqu'il s'agit de grands objets — coûts en mémoire/temps pour la copie.