Über flache und tiefe Kopien von Python / Ruby

Über flache und tiefe Kopien von Python / Ruby

In Python und Ruby ist die Zuweisung im Gegensatz zu PHP keine Kopie, und die Zuweisung bedeutet "Erstellen einer Einschränkung zwischen dem Ziel und dem Objekt". Es war schwierig, die Bedeutung von "Schaffung einer Beschränkung zwischen dem Ziel und dem Objekt" zu verstehen, und ich habe es als Memorandum belassen, um das Verständnis der Bedeutungen von "unveränderlich" und "veränderlich" basierend auf der Stichprobe zu vertiefen. Hier wurden Python3.6.2 und Ruby2.4.1 verwendet.

Auswechslung

Ganzzahlige Substitution

Aus den Ergebnissen von Python 3.6 und Ruby 2.4 geht hervor, dass sich die "ID" von "a" ändert, wenn die Variable "a" manipuliert wird, und sie ist unveränderlich (kann nicht geändert werden), da sie für das ganzzahlige Objekt "3" nicht geändert werden kann. Hier wird ein solches Objekt der Einfachheit halber als unveränderliches Objekt behandelt.

Für Python 3.6

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

Ausgabeergebnis


id_3:1623654960, id_a:1623654960
id_b:1623654960
id_3:1623654960, id_4:1623654992, id_a:1623654992, id_b:1623654960

Im Fall von Python3.6 gibt es Fälle, in denen sich die ID sogar für Ganzzahlen mit demselben Wert wie unten gezeigt unterscheidet.

class A:
    def get(self):
        print(id(99999999999999999999999999999))


class B:
    def get(self):
        print(id(99999999999999999999999999999))

A().get()
B().get()

Ausgabeergebnis


2812564670744
2812564671464

Für Ruby 2.4

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]

Ausgabeergebnis


id_3:7, id_a:7
id_b:7
id_3:7, id_4:9, id_a:9, id_b:7

Selbst im Fall von Ruby gibt es Fälle, in denen die "ID" auch für Ganzzahlen mit demselben Wert wie unten gezeigt unterschiedlich ist.

p 99999999999999999999999.object_id
p 99999999999999999999999.object_id

Ausgabeergebnis


25133964
25133856

Zuordnung von Array (Ruby) und Liste (Python)

Aus den Ergebnissen von Python 3.6 und Ruby 2.4 geht hervor, dass der Wert, selbst wenn er durch die Operation "a" geändert wird, dieselbe "ID" ist und in einen anderen Wert geändert werden kann. Das heißt, es ist veränderlich (veränderbar). Hier wird ein solches Objekt der Einfachheit halber als veränderliches Objekt behandelt. Wenn der Wert von "a" "b" zugewiesen wird, ist die "id" dieselbe. Wenn also der Wert durch Manipulieren von "a" geändert wird, ändert sich auch "b".

Für Python 3.6

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)

Ausgabeergebnis


id_a:4332032456, id_b:4332032456
[1, 2, 3] [1, 2, 3]
id_a:4332032456, id_b:4332032456
[1, 4, 3] [1, 4, 3]

Für Ruby 2.4

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

Ausgabeergebnis


id_a:70131497645860, id_b:70131497645860
[1, 2, 3]
[1, 2, 3]
id_a:70131497645860, id_b:70131497645860
[1, 4, 3]
[1, 4, 3]

Flache Kopie

Im Fall eines veränderlichen Objekts, wie im obigen Beispiel, ist, wenn der Wert von "a" "b" zugewiesen ist, die "id" dieselbe. Wenn also der Wert durch Manipulieren von "a" geändert wird, "b" `Ändert sich auch. Sie müssen eine Kopie erstellen, um den Wert von "b" unabhängig von "a" zu machen. Im Fall der Liste oder des Arrays in diesem Beispiel kann dies durch Erstellen einer flachen Kopie realisiert werden. Im folgenden Beispiel ändert sich durch Erstellen einer flachen Kopie der Wert von "b" nicht, selbst wenn der Wert durch die Operation "a" geändert wird.

Für Python 3.6

Eine flache Kopie kann durch Ersetzen der Funktion "copy.copy" oder "a [:]" erstellt werden.

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)

Ausgabeergebnis


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]

Für Ruby 2.4

Eine flache Kopie kann mit "Object.clone" oder "Object.dup" erstellt werden. Darüber hinaus [hier](https://ja.stackoverflow.com/questions/27101/ruby%E3%81%AEclone%E3%81%A8dup%E3%81%A8activerecord%E3%81%AEclone%E3%81% Das Verhalten unterscheidet sich von "ActiveModel.clone" und "ActiveModel.dup" von "Rails" wie A8dup% E3% 81% AF% E5% 88% A5% E7% 89% A9).

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

Ausgabeergebnis


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]

Fälle, in denen flaches Kopieren nicht ausreicht

Im folgenden Beispiel, in dem das Element der Liste eine Liste und das Element des Arrays ein Array ist, gibt es beispielsweise ein anderes veränderbares Objekt aus dem veränderlichen Objekt, selbst wenn eine flache Kopie erstellt wird, indem "a [0]" manipuliert wird. Der Wert von "b [0]" wird geändert. Dies verhält sich für Python 3.6 und Ruby 2.4 gleich.

Für Python 3.6

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)

Ausgabeergebnis


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']

Für Ruby 2.4

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

Ausgabeergebnis


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"]

Tiefe Kopie

Wenn ein veränderbares Objekt ein anderes veränderbares Objekt enthält, bei dem es sich um eine "flache Kopie ist nicht genug" handelt, müssen Sie eine tiefe Kopie anstelle einer flachen Kopie erstellen, um den Wert von "b" nach "a" vollständig zu kopieren. Es gibt.

Für Python 3.6

Eine tiefe Kopie kann mit copy.deepcopy erreicht werden.

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)

Ausgabeergebnis


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']

Für Ruby 2.4

Eine tiefe Kopie kann mit Marshal.load und Marshal.dump erreicht werden.

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

Ausgabeergebnis


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"]

Ergänzung

Über Zeichenketten in Ruby

In Ruby 2.4 wird das Zeichenfolgenliteral wie unten gezeigt zu einem veränderlichen Objekt. Soweit auf hier verwiesen wird, ist das String-Literal ein unveränderliches Objekt in Ruby3. In Python3.6 muss in einen Listentyp mit b = list (a) konvertiert werden, um wie folgt damit umgehen zu können.

a = "abc"
puts 'id_a:%d' % [a.object_id]
a[0] = "A"
puts 'id_a:%d' % [a.object_id]

Ausgabeergebnis


id_a:70186456022160
id_a:70186456022160

Informationen zur Zuordnung nach PHP-Referenz

Entspricht die Zuordnung bei PHP einer tiefen Kopie? Selbst wenn im folgenden Beispiel "$ a = [5];", "$ b" auf "$ a" verweist, handelt es sich also um den Wert, auf den "$ a" verweist. Eine Substitution durch Referenz wie "$ a = & $ b;" in PHP kann in Python oder Ruby nicht realisiert werden.

<?php

$a = [3];
$b = &$a;
$a = [5];
print_r($a);
print_r($b);

Ausgabeergebnis


Array
(
    [0] => 5
)
Array
(
    [0] => 5
)

Über flache und tiefe Kopien

In diesem Beispiel werden Listen und Arrays als Beispiele verwendet, aber der Unterschied zwischen flacher und tiefer Kopie kann auch in den folgenden Fällen unterschieden werden.

Für Python 3.6

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

Ausgabeergebnis


5
5
7

Für Ruby 2.4

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

Ausgabeergebnis


5
5
7

Recommended Posts

Über flache und tiefe Kopien von Python / Ruby
Flache Python-Kopie und tiefe Kopie
Flache Python-Kopie und tiefe Kopie
Zusammenfassung der Korrespondenz zwischen Ruby- und Python-Array-Operationen
Angeben des Bereichs von Ruby- und Python-Arrays
Ruby, Python und Map
Python und Ruby teilen sich
Vergleich von Python und Ruby (Environment / Grammar / Literal Edition)
[Python] Kapitel 01-02 Über Python (Ausführung und Installation der Entwicklungsumgebung)
Vergleich von CoffeeScript mit JavaScript-, Python- und Ruby-Grammatik
Versionsverwaltung von Node, Ruby und Python mit anyenv
Python auf Ruby und wütend Ruby auf Python
Informationen zu Python-Objekten und -Klassen
Informationen zu Python-Variablen und -Objekten
Python und Ruby Slice Memo
Über verschiedene Codierungen von Python 3
Über Python, len () und randint ()
Über Perl, Python, PHP, Ruby
Ruby- und Python-Syntax ~ branch ~
Über Python und reguläre Ausdrücke
Über die Funktionen von Python
Quellinstallation und Installation von Python
Informationen zu Python- und Betriebssystemoperationen
Python # Über Referenz und Kopie
Über Python sort () und reverse ()
Python vs Ruby "Deep Learning from Grund" Kapitel 1 Diagramm der Sin-Funktion und der Cos-Funktion
Zusammenfassung der Unterstützung von Hash-Operationen (Dictionary) für Ruby und Python
Umgebungskonstruktion von Python und OpenCV
Unterschied zwischen Ruby und Python Split
Die Geschichte von Python und die Geschichte von NaN
Installation von SciPy und matplotlib (Python)
Scraping mit Node, Ruby und Python
Über Python-Diktat und sortierte Funktionen
Über Python und Cython dtype
Über Python Pickle (cPickle) und Marschall
[Python] Über Executor und zukünftige Klassen
Über Python, aus und importieren, als
Dies und das von Python-Eigenschaften
Koexistenz von Python2 und 3 mit CircleCI (1.0)
Informationen zur Grundlagenliste der Python-Grundlagen
Zusammenfassung der Python-Indizes und -Slices
Reputation von Python-Büchern und Nachschlagewerken
Ich habe die Geschwindigkeit von Hash mit Topaz, Ruby und Python verglichen
Installation von Visual Studio Code und Installation von Python
Informationen zum Erstellen einer GUI mit TKinter of Python
Unterschiede zwischen Ruby und Python im Umfang
Extraktion von tweet.js (json.loads und eval) (Python)
Bedeutung von Deep-Learning-Modellen und -Parametern
Informationen zur virtuellen Umgebung von Python Version 3.7
Über sensor_mode und Blickwinkel der Picamera
Memorandum von Python-Anfängern
Verbinde viel Python oder und und
Mit Ruby (Rails) verschlüsseln und mit Python entschlüsseln
Eine Geschichte über Python Pop und Append
Einfache Einführung in die Python3-Serie und OpenCV3
[Python] Verschiedene Kombinationen von Zeichenketten und Werten
Einfaches Web-Scraping mit Python und Ruby
Hinweis auf Probleme hinsichtlich der Koexistenz des Python 2/3-Systems
[Python] Kapitel 02-04 Grundlagen des Python-Programms (Informationen zu Kommentaren)