Notez que l'article "A propos de la référence python" était intéressant. Dans cet article,
Quand j'ai commencé python, la première chose sur laquelle je suis tombé par hasard a été la mystérieuse explication que l'on voit souvent partout: "Tous les arguments python sont passés par référence."
Il y avait un passage. Comme déjà souligné dans les commentaires, pour être plus précis, "tous les arguments Python sont passés par référence", mais de toute façon, il semble qu'il n'y ait pas de passage par valeur en Python! J'écrivais un article "Passer par valeur, passer par référence, passer par référence" avec presque le même thème, où entiers et virgules flottantes J'ai écrit que le nombre est passé par valeur en Python. En fait, il a donné une explication cohérente, et l'article original
Lorsqu'un nouvel objet lui-même est affecté à une variable, il fera référence à l'endroit où le nouvel objet a été créé au lieu de la destination de référence précédente.
Cette partie est la même que ce que j'ai écrit dans l'explication sur le passage des références par valeur. Cependant, j'ai regardé les commentaires et j'ai peut-être écrit quelque chose d'un peu inexact, alors je l'ai étudié en détail.
Considérez le code Python suivant.
ex1.py
a = 1
b = a
print("a : value = " + str(a) + "\tid = " + str(id(a)))
print("b : value = " + str(b) + "\tid = " + str(id(b)))
a : value = 1 id = 4360526320
b : value = 1 id = 4360526320
Il s'agit certainement de "passer par référence", pas de "passer par valeur". Parce que si vous passez par valeur, id (valeur du pointeur) ne doit pas correspondre comme le C ++ suivant.
ex1.cpp
#include <iostream>
int main(){
int a = 1;
int b = a;
std::cout << "a : value = " << a << "\tid = " << &a << "\n";
std::cout << "b : value = " << b << "\tid = " << &b << "\n";
return 0;
}
a : value = 1 id = 0x7fff50360ae8
b : value = 1 id = 0x7fff50360ae4
Et si cela arrivait ensuite?
ex2.py
a = 1
b = a
print("a : value = " + str(a) + "\tid = " + str(id(a)))
print("b : value = " + str(b) + "\tid = " + str(id(b)) + "\n")
b = 2
print("a : value = " + str(a) + "\tid = " + str(id(a)))
print("b : value = " + str(b) + "\tid = " + str(id(b)))
a : value = 1 id = 4348889584
b : value = 1 id = 4348889584
a : value = 1 id = 4348889584
b : value = 2 id = 4348889616
ex2.cpp
#include <iostream>
int main(){
int a = 1;
int b = a;
std::cout << "a : value = " << a << "\tid = " << &a << "\n";
std::cout << "b : value = " << b << "\tid = " << &b << "\n\n";
b = 2;
std::cout << "a : value = " << a << "\tid = " << &a << "\n";
std::cout << "b : value = " << b << "\tid = " << &b << "\n";
return 0;
}
a : value = 1 id = 0x7fff561cdae8
b : value = 1 id = 0x7fff561cdae4
a : value = 1 id = 0x7fff561cdae8
b : value = 2 id = 0x7fff561cdae4
De cette façon, contrairement au C ++, en Python, si vous attribuez une valeur différente, l'id changera également. En d'autres termes, la destination de référence change. Qu'en est-il des affectations composées comme + =?
ex3.py
a = 1
b = a
print("a : value = " + str(a) + "\tid = " + str(id(a)))
print("b : value = " + str(b) + "\tid = " + str(id(b)) + "\n")
b += 2
print("a : value = " + str(a) + "\tid = " + str(id(a)))
print("b : value = " + str(b) + "\tid = " + str(id(b)))
a : value = 1 id = 4507830768
b : value = 1 id = 4507830768
a : value = 1 id = 4507830768
b : value = 3 id = 4507830832
C'est pareil. Comme vous pouvez le voir dans le commentaire de l'article original, «b + = 2» est en fait appelé «b = b + 2», et une nouvelle référence est également attribuée. En d'autres termes, en Python, "Chaque fois que vous modifiez la valeur d'un entier, un nouvel objet est créé dans la mémoire et il est attribué, donc l'id change également." En d'autres termes, en Python, «une fois que vous générez un entier en mémoire, vous ne pouvez pas le changer», ce qui s'appelle «** immuable ». Le contraire est " mutable **". D'autres types immuables incluent les nombres à virgule flottante, les bourians, les chaînes, les taples et None, et ce qui est essentiel en Python est "mutable ou non" plutôt que "passer par valeur". Ce sera. Je ne savais pas.
À propos, Java a quelque chose de similaire à l'exemple Python ci-dessus. Classes wrapper telles que String et Integer et Double.
Ex1.java
class Ex1{
public static void main(String[] args){
String s1 = "foo";
String s2 = s1;
System.out.println("s1 : " + s1);
System.out.println("s2 : " + s2 + "\n");
s2 += "bar";
System.out.println("s1 : " + s1);
System.out.println("s2 : " + s2 + "\n");
Integer i1 = 1;
Integer i2 = i1;
System.out.println("i1 : " + i1);
System.out.println("i2 : " + i2 + "\n");
i2 += 2;
System.out.println("i1 : " + i1);
System.out.println("i2 : " + i2);
}
}
s1 : foo
s2 : foo
s1 : foo
s2 : foobar
i1 : 1
i2 : 1
i1 : 1
i2 : 3
De cette façon, les chaînes Java et les entiers se comportent comme des valeurs de passage, bien qu'il s'agisse de types référence. Essayons de décompiler le fichier de classe créé en compilant ce qui précède en utilisant jad.
Ex1.jad
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: Ex1.java
import java.io.PrintStream;
class Ex1
{
Ex1()
{
}
public static void main(String args[])
{
String s = "foo";
String s1 = s;
System.out.println((new StringBuilder()).append("s1 : ").append(s).toString());
System.out.println((new StringBuilder()).append("s2 : ").append(s1).append("\n").toString());
s1 = (new StringBuilder()).append(s1).append("bar").toString();
System.out.println((new StringBuilder()).append("s1 : ").append(s).toString());
System.out.println((new StringBuilder()).append("s2 : ").append(s1).append("\n").toString());
Integer integer = Integer.valueOf(1);
Integer integer1 = integer;
System.out.println((new StringBuilder()).append("i1 : ").append(integer).toString());
System.out.println((new StringBuilder()).append("i2 : ").append(integer1).append("\n").toString());
integer1 = Integer.valueOf(integer1.intValue() + 2);
System.out.println((new StringBuilder()).append("i1 : ").append(integer).toString());
System.out.println((new StringBuilder()).append("i2 : ").append(integer1).toString());
}
}
C'est un peu difficile à voir, mais les deux sont réécrits en tant qu'affectations composées pour créer un nouvel objet et modifier la référence. Quand je ne le savais pas encore, j'ai dit: «Je veux renvoyer plusieurs entiers et doubles dans une méthode, mais il est difficile de créer une classe juste pour cela, et les entiers et les doubles ne peuvent être passés que par valeur. J'ai pensé: "N'est-il pas possible de le faire passer pour un argument?"
Pour résumer ce qui précède, nous concluons que ** les types immuables ne vous permettent pas de changer la valeur d'un objet une fois créé, donc même le passage par référence se comportera sensiblement comme le passage par valeur **. Devenir. Excusez-moi.
Recommended Posts