En Python et Ruby, contrairement à PHP, l'affectation n'est pas une copie et l'affectation signifie «créer une contrainte entre la cible et l'objet». Je l'ai laissé comme mémorandum pour approfondir ma compréhension de la signification de «créer une contrainte entre la cible et l'objet» et la signification de «immuable» et «mutable» basée sur l'échantillon. Ici, Python3.6.2 et Ruby2.4.1 ont été utilisés.
D'après les résultats de Python 3.6 et Ruby 2.4 ci-dessous, lorsque la variable ʻa est manipulée, l''id
de ʻa change, et il est immuable (ne peut pas être changé) car il ne peut pas être changé pour l'objet entier
3`. Ici, pour des raisons de commodité, un tel objet est traité comme un objet immuable.
a = 3
print("id_3:%d, id_a:%d" % (id(3), id(a)))
b = a
print("id_b:%d" % id(b))
a += 1
print("id_3:%d, id_4:%d, id_a:%d, id_b:%d" % (id(3), id(4), id(a), id(b)))
Résultat de sortie
id_3:1623654960, id_a:1623654960
id_b:1623654960
id_3:1623654960, id_4:1623654992, id_a:1623654992, id_b:1623654960
Dans le cas de Python3.6, il y a des cas où «id» est différent même pour les entiers avec la même valeur comme indiqué ci-dessous.
class A:
def get(self):
print(id(99999999999999999999999999999))
class B:
def get(self):
print(id(99999999999999999999999999999))
A().get()
B().get()
Résultat de sortie
2812564670744
2812564671464
a = 3
puts 'id_3:%d, id_a:%d' % [3.object_id, a.object_id]
b = a
puts 'id_b:%d' % [b.object_id]
a += 1
puts 'id_3:%d, id_4:%d, id_a:%d, id_b:%d' % [3.object_id, 4.object_id, a.object_id, b.object_id]
Résultat de sortie
id_3:7, id_a:7
id_b:7
id_3:7, id_4:9, id_a:9, id_b:7
Même dans le cas de Ruby, il y a des cas où «id» est différent même pour les entiers avec la même valeur comme indiqué ci-dessous.
p 99999999999999999999999.object_id
p 99999999999999999999999.object_id
Résultat de sortie
25133964
25133856
D'après les résultats de Python 3.6 et Ruby 2.4 ci-dessous, même si la valeur est modifiée en opérant ʻa, c'est le même ʻid
et peut être changé en une valeur différente. Autrement dit, il est mutable (modifiable). Ici, pour plus de commodité, un tel objet est traité comme un objet mutable.
Lorsque la valeur de ʻa est assignée à
b, ʻid
est le même, donc si la valeur est modifiée en manipulant ʻa,
b` change également.
a = [1,2,3]
b = a
print("id_a:%d, id_b:%d" % (id(a), id(b)))
print(a, b)
a[1] = 4
print("id_a:%d, id_b:%d" % (id(a), id(b)))
print(a, b)
Résultat de sortie
id_a:4332032456, id_b:4332032456
[1, 2, 3] [1, 2, 3]
id_a:4332032456, id_b:4332032456
[1, 4, 3] [1, 4, 3]
a = [1,2,3]
b = a
puts 'id_a:%d, id_b:%d' % [a.object_id, b.object_id]
p a, b
a[1] = 4
puts 'id_a:%d, id_b:%d' % [a.object_id, b.object_id]
p a, b
Résultat de sortie
id_a:70131497645860, id_b:70131497645860
[1, 2, 3]
[1, 2, 3]
id_a:70131497645860, id_b:70131497645860
[1, 4, 3]
[1, 4, 3]
Dans le cas d'un objet mutable, comme dans l'exemple ci-dessus, si la valeur de ʻa est assignée à
b, l''id
est le même, donc si la valeur est modifiée en manipulant ʻa,
b ʻAussi change. Vous devez faire une copie pour rendre la valeur de «b» indépendante de «a». Dans le cas de la liste ou du tableau dans cet exemple, il peut être réalisé en faisant une copie superficielle.
Dans l'exemple ci-dessous, en faisant une copie superficielle, la valeur de «b» ne change pas même si la valeur est modifiée par l'opération de «a».
Une copie superficielle peut être faite en remplaçant la fonction copy.copy
ou ʻa [:]`.
import copy as cp
a = [1,2,3]
b = cp.copy(a)
print("id_a:%d, id_b:%d" % (id(a), id(b)))
print(a, b)
a[1] = 4
print("id_a:%d, id_b:%d" % (id(a), id(b)))
print(a, b)
b = a[:]
print("id_a:%d, id_b:%d" % (id(a), id(b)))
print(a, b)
a[1] = 3
print("id_a:%d, id_b:%d" % (id(a), id(b)))
print(a, b)
Résultat de sortie
id_a:4460690760, id_b:4460690888
[1, 2, 3] [1, 2, 3]
id_a:4460690760, id_b:4460690888
[1, 4, 3] [1, 2, 3]
id_a:4460690760, id_b:4460691272
[1, 4, 3] [1, 4, 3]
id_a:4460690760, id_b:4460691272
[1, 3, 3] [1, 4, 3]
Une copie superficielle peut être obtenue en utilisant ʻObject.clone ou ʻObject.dup
.
En outre, [ici](https://ja.stackoverflow.com/questions/27101/ruby%E3%81%AEclone%E3%81%A8dup%E3%81%A8activerecord%E3%81%AEclone%E3%81% A8dup% E3% 81% AF% E5% 88% A5% E7% 89% A9) Le comportement est différent de ʻActiveModel.clone et ʻActiveModel.dup
de Rails
.
a = [1,2,3]
b = a.clone
puts 'id_a:%d, id_b:%d' % [a.object_id, b.object_id]
p a, b
a[1] = 4
puts 'id_a:%d, id_b:%d' % [a.object_id, b.object_id]
p a, b
b = a.dup
puts 'id_a:%d, id_b:%d' % [a.object_id, b.object_id]
p a, b
a[1] = 3
puts 'id_a:%d, id_b:%d' % [a.object_id, b.object_id]
p a, b
Résultat de sortie
id_a:70245067666580, id_b:70245067666520
[1, 2, 3]
[1, 2, 3]
id_a:70245067666580, id_b:70245067666520
[1, 4, 3]
[1, 2, 3]
id_a:70245067666580, id_b:70245067665580
[1, 4, 3]
[1, 4, 3]
id_a:70245067666580, id_b:70245067665580
[1, 3, 3]
[1, 4, 3]
Par exemple, dans l'exemple suivant où il y a une liste dans l'élément de la liste et un tableau dans l'élément du tableau, c'est-à-dire qu'il y a un autre objet mutable de l'objet mutable, même si vous faites une copie superficielle, vous pouvez opérer ʻa [0] `. La valeur de «b [0]» est modifiée. Cela se comporte de la même manière pour Python 3.6 et Ruby 2.4.
import copy as cp
a = [[1,2,3], "abc"]
b = cp.copy(a)
print("id_a:%d, id_b:%d" % (id(a), id(b)))
print("id_a[0]:%d, id_b[0]:%d" % (id(a[0]), id(b[0])))
print("id_a[1]:%d, id_b[1]:%d" % (id(a[1]), id(b[1])))
print(a, b)
a[0][1] = 4
a[1] = "def"
print("id_a:%d, id_b:%d" % (id(a), id(b)))
print("id_a[0]:%d, id_b[0]:%d" % (id(a[0]), id(b[0])))
print("id_a[1]:%d, id_b[1]:%d" % (id(a[1]), id(b[1])))
print(a, b)
b = a[:]
print("id_a:%d, id_b:%d" % (id(a), id(b)))
print("id_a[0]:%d, id_b[0]:%d" % (id(a[0]), id(b[0])))
print("id_a[1]:%d, id_b[1]:%d" % (id(a[1]), id(b[1])))
print(a, b)
a[0][1] = 3
a[1] = "abc"
print("id_a:%d, id_b:%d" % (id(a), id(b)))
print("id_a[0]:%d, id_b[0]:%d" % (id(a[0]), id(b[0])))
print("id_a[1]:%d, id_b[1]:%d" % (id(a[1]), id(b[1])))
print(a, b)
Résultat de sortie
id_a:4393106888, id_b:4393107272
id_a[0]:4393106760, id_b[0]:4393106760
id_a[1]:4391239728, id_b[1]:4391239728
[[1, 2, 3], 'abc'] [[1, 2, 3], 'abc']
id_a:4393106888, id_b:4393107272
id_a[0]:4393106760, id_b[0]:4393106760
id_a[1]:4392739984, id_b[1]:4391239728
[[1, 4, 3], 'def'] [[1, 4, 3], 'abc']
id_a:4393106888, id_b:4393112648
id_a[0]:4393106760, id_b[0]:4393106760
id_a[1]:4392739984, id_b[1]:4392739984
[[1, 4, 3], 'def'] [[1, 4, 3], 'def']
id_a:4393106888, id_b:4393112648
id_a[0]:4393106760, id_b[0]:4393106760
id_a[1]:4391239728, id_b[1]:4392739984
[[1, 3, 3], 'abc'] [[1, 3, 3], 'def']
a = [[1,2,3], "abc"]
b = a.clone
puts 'id_a:%d, id_b:%d' % [a.object_id, b.object_id]
puts 'id_a[0]:%d, id_b[0]:%d' % [a[0].object_id, b[0].object_id]
puts 'id_a[1]:%d, id_b[1]:%d' % [a[1].object_id, b[1].object_id]
p a, b
a[0][1] = 4
a[1] = "def"
puts 'id_a:%d, id_b:%d' % [a.object_id, b.object_id]
puts 'id_a[0]:%d, id_b[0]:%d' % [a[0].object_id, b[0].object_id]
puts 'id_a[1]:%d, id_b[1]:%d' % [a[1].object_id, b[1].object_id]
p a, b
b = a.dup
puts 'id_a:%d, id_b:%d' % [a.object_id, b.object_id]
puts 'id_a[0]:%d, id_b[0]:%d' % [a[0].object_id, b[0].object_id]
puts 'id_a[1]:%d, id_b[1]:%d' % [a[1].object_id, b[1].object_id]
p a, b
a[0][1] = 3
a[1] = "abc"
puts 'id_a:%d, id_b:%d' % [a.object_id, b.object_id]
puts 'id_a[0]:%d, id_b[0]:%d' % [a[0].object_id, b[0].object_id]
puts 'id_a[1]:%d, id_b[1]:%d' % [a[1].object_id, b[1].object_id]
p a, b
Résultat de sortie
id_a:70199714913920, id_b:70199714913860
id_a[0]:70199714913960, id_b[0]:70199714913960
id_a[1]:70199714913940, id_b[1]:70199714913940
[[1, 2, 3], "abc"]
[[1, 2, 3], "abc"]
id_a:70199714913920, id_b:70199714913860
id_a[0]:70199714913960, id_b[0]:70199714913960
id_a[1]:70199714912900, id_b[1]:70199714913940
[[1, 4, 3], "def"]
[[1, 4, 3], "abc"]
id_a:70199714913920, id_b:70199714912200
id_a[0]:70199714913960, id_b[0]:70199714913960
id_a[1]:70199714912900, id_b[1]:70199714912900
[[1, 4, 3], "def"]
[[1, 4, 3], "def"]
id_a:70199714913920, id_b:70199714912200
id_a[0]:70199714913960, id_b[0]:70199714913960
id_a[1]:70199714911480, id_b[1]:70199714912900
[[1, 3, 3], "abc"]
[[1, 3, 3], "def"]
Si un objet mutable contient un autre objet mutable, qui est une "copie superficielle n'est pas assez de cas", vous devez faire une copie profonde au lieu d'une copie superficielle pour copier complètement la valeur de b
dans ʻa`. Il y a.
Une copie complète peut être réalisée avec copy.deepcopy
.
import copy as cp
a = [[1,2,3], "abc"]
b = cp.deepcopy(a)
print("id_a:%d, id_b:%d" % (id(a), id(b)))
print("id_a[0]:%d, id_b[0]:%d" % (id(a[0]), id(b[0])))
print("id_a[1]:%d, id_b[1]:%d" % (id(a[1]), id(b[1])))
print(a, b)
a[0][1] = 4
a[1] = "def"
print("id_a:%d, id_b:%d" % (id(a), id(b)))
print("id_a[0]:%d, id_b[0]:%d" % (id(a[0]), id(b[0])))
print("id_a[1]:%d, id_b[1]:%d" % (id(a[1]), id(b[1])))
print(a, b)
Résultat de sortie
id_a:4306767304, id_b:4306767688
id_a[0]:4306767176, id_b[0]:4306773064
id_a[1]:4304900144, id_b[1]:4304900144
[[1, 2, 3], 'abc'] [[1, 2, 3], 'abc']
id_a:4306767304, id_b:4306767688
id_a[0]:4306767176, id_b[0]:4306773064
id_a[1]:4306400400, id_b[1]:4304900144
[[1, 4, 3], 'def'] [[1, 2, 3], 'abc']
Une copie complète peut être réalisée avec «Marshal.load» et «Marshal.dump».
a = [[1,2,3], "abc"]
b = Marshal.load(Marshal.dump(a))
puts 'id_a:%d, id_b:%d' % [a.object_id, b.object_id]
puts 'id_a[0]:%d, id_b[0]:%d' % [a[0].object_id, b[0].object_id]
puts 'id_a[1]:%d, id_b[1]:%d' % [a[1].object_id, b[1].object_id]
p a, b
a[0][1] = 4
a[1] = "def"
puts 'id_a:%d, id_b:%d' % [a.object_id, b.object_id]
puts 'id_a[0]:%d, id_b[0]:%d' % [a[0].object_id, b[0].object_id]
puts 'id_a[1]:%d, id_b[1]:%d' % [a[1].object_id, b[1].object_id]
p a, b
Résultat de sortie
id_a:70274700700880, id_b:70274700700800
id_a[0]:70274700700940, id_b[0]:70274700700780
id_a[1]:70274700700900, id_b[1]:70274700700760
[[1, 2, 3], "abc"]
[[1, 2, 3], "abc"]
id_a:70274700700880, id_b:70274700700800
id_a[0]:70274700700940, id_b[0]:70274700700780
id_a[1]:70274700699900, id_b[1]:70274700700760
[[1, 4, 3], "def"]
[[1, 2, 3], "abc"]
Dans Ruby 2.4, la chaîne de caractères littérale devient un objet mutable comme indiqué ci-dessous. En ce qui concerne here, la chaîne littérale sera un objet immuable dans Ruby3.
En Python3.6, il est nécessaire de convertir en un type de liste avec b = list (a)
pour le gérer comme suit.
a = "abc"
puts 'id_a:%d' % [a.object_id]
a[0] = "A"
puts 'id_a:%d' % [a.object_id]
Résultat de sortie
id_a:70186456022160
id_a:70186456022160
Dans le cas de PHP, l'affectation correspond-elle à une copie profonde? Dans l'exemple ci-dessous, même si $ a = [5];
, $ b
fait référence à $ a
, il s'agit donc de la valeur référencée par $ a
. La substitution par référence telle que $ a = & $ b;
en PHP ne peut pas être réalisée en Python ou Ruby.
<?php
$a = [3];
$b = &$a;
$a = [5];
print_r($a);
print_r($b);
Résultat de sortie
Array
(
[0] => 5
)
Array
(
[0] => 5
)
Dans l'exemple ici, les listes et les tableaux sont pris comme exemples, mais la différence entre copie superficielle et copie profonde peut être discriminée même dans les cas suivants.
import copy
class Test1:
def __init__(self):
self.a = 0
def set(self, n):
self.a = n
def get(self):
print(self.a)
class Test2:
def __init__(self, t):
self.t1 = t
def set(self, n):
self.t1.set(n)
def get(self):
self.t1.get()
a = Test2(Test1())
b = copy.copy(a)
c = copy.deepcopy(a)
a.set(3)
b.set(5)
c.set(7)
a.get()
b.get()
c.get()
Résultat de sortie
5
5
7
class Test1
def initialize
@a = 0
end
def set(n)
@a = n
end
def get()
puts @a
end
end
class Test2
def initialize(t1)
@t1 = t1
end
def set(n)
@t1.set(n)
end
def get()
@t1.get
end
end
a = Test2.new(Test1.new)
b = a.clone
c = Marshal.load(Marshal.dump(a))
a.set(3)
b.set(5)
c.set(7)
a.get
b.get
c.get
Résultat de sortie
5
5
7
Recommended Posts