Расскажите девушке о присваивании python-S01E11 и анализе механизма копирования объектов

искусственный интеллект Python алгоритм задняя часть
Расскажите девушке о присваивании python-S01E11 и анализе механизма копирования объектов

Добро пожаловать в общедоступный номер: специалист по данным python

【Ключевые моменты, которые стоит увидеть в первую очередь】

1. Модификация изменяемых объектов на месте
2. Как получить независимую копию объекта
3. Сравнение, равенство и проблемы истинности

Наша сегодняшняя тема должна начаться с «модификации изменяемых объектов на месте», что является примечательной проблемой.

Как мы говорили в предыдущем эпизоде, операции присваивания всегда хранят ссылки на объекты, а не копии этих объектов. Поскольку операции присваивания в этом процессе будут генерировать несколько ссылок на один и тот же объект, нам нужно знать о возможных проблемах с «изменяемыми объектами» здесь:Изменение изменяемого объекта на месте может повлиять на другие переменные в программе, которые ссылаются на этот объект.Если вы не хотите видеть этот сценарий, вам нужно явно скопировать объект, а не просто назначать его.

X = [1,2,3,4,5]
L = ['a', X, 'b']
D = {'x':X, 'y':2}

print(L)
print(D)

['a', [1, 2, 3, 4, 5], 'b']
{'y': 2, 'x': [1, 2, 3, 4, 5]}

В этом примере мы видим, что список [1, 2, 3, 4, 5] имеет три ссылки, на которые ссылается переменная X, на которую ссылается элемент внутри списка L и на который ссылается элемент внутри словаря D.Затем использование любой из этих трех ссылок для изменения списка [1, 2, 3, 4, 5] также изменит объекты двух других ссылок., например, я использую L для изменения второго элемента [1, 2, 3, 4, 5], и результат операции очень очевиден.

X = [1,2,3,4,5]
L = ['a', X, 'b']
D = {'x':X, 'y':2}

L[1][2] = 'changed'
print(X)
print(L)
print(D)

[1, 2, 'changed', 4, 5]
['a', [1, 2, 'changed', 4, 5], 'b']
{'x': [1, 2, 'changed', 4, 5], 'y': 2}

[Сестра сказала] Пожалуйста, объезжайте, если есть ямы, в этих местах очень легко ошибиться.

Ссылки — это аналог указателей более высокого уровня в других языках. Это может помочь вам передавать большие объекты в любом месте области действия программы, не создавая копии по пути, и играть роль оптимизации программы.

[Сестра сказала] Но что, если я не хочу делиться ссылкой на объект, а хочу получить независимую копию объекта?

Можно подумать, что этот слой действительно хорош, на самом деле это очень просто, обычно используемые методы следующие:

Первый способ: выражение шардинга может вернуть новую копию объекта, а выражение неограниченного шардинга может полностью скопировать список

L = [1,2,3,4,5]
C = L[1:3]
C[0] = 8
print(C)
print(L)

[8, 3]
[1, 2, 3, 4, 5]

L = [1,2,3,4,5]
C = L[:]
C[0] = 8
print(C)
print(L)

[8, 2, 3, 4, 5]
[1, 2, 3, 4, 5]

Видно, что с помощью выражения фрагментации получается новая копия списка C, и значение исходного списка L не изменится при модификации этого списка.

Второй метод: метод копирования словаря также может обеспечить полную копию словаря:

D = {'a':1, 'b':2}
B = D.copy()
B['a'] = 888
print(B)
print(D)

{'a': 888, 'b': 2}
{'a': 1, 'b': 2}

Третий тип: встроенный список функций может генерировать копию

L = [1,2,3,4]
C = list(L)
C[0] = 888
print(C)
print(L)

[888, 2, 3, 4]
[1, 2, 3, 4]

Наконец, давайте рассмотрим более сложный пример.

B получает копию списка A посредством операции неограниченной фрагментации. Модификация элементов в списке B не повлияет на A, например, изменение значения, например замена ссылки другой ссылкой на список:

L = [1,2,3,4]
A = [1,2,3,L]
B = A[:]
B[1] = 333
B[3] = ['888','999']
print(B)
print(A)
print(L)

[1, 333, 3, ['888', '999']]
[1, 2, 3, [1, 2, 3, 4]]
[1, 2, 3, 4]

Но что, если это сценарий?

L = [1,2,3,4]
A = [1,2,3,L]
B = A[:]
B[1] = 333
B[3][1] = ['changed']
print(B)
print(A)
print(L)

[1, 333, 3, [1, ['changed'], 3, 4]]
[1, 2, 3, [1, ['changed'], 3, 4]]
[1, ['changed'], 3, 4]

Поскольку последний элемент B также является ссылкой на список L (его можно рассматривать как получение адреса L), дальнейшая модификация содержащихся элементов объекта списка через эту ссылку также повлияет на сами A и L.

Поэтому операция неограниченной фрагментации и метод копирования словаря могут выполнять только присваивания верхнего уровня.На верхнем уровне, если это числовой объект, значение копируется, а если это ссылка на объект, ссылка копируется напрямую, поэтому на следующем уровне все еще существует скрытое явление общей ссылки.

Если вы хотите добиться полного и независимого нисходящего, глубокого копирования ссылок на каждом уровне, вы должны использовать метод deepcopy модуля копирования.

import copy

L = [1,2,3,4]
A = [1,2,3,L]
B = copy.deepcopy(A)

B[3][1] = ['changed']
print(B)
print(A)
print(L)

[1, 2, 3, [1, ['changed'], 3, 4]]
[1, 2, 3, [1, 2, 3, 4]]
[1, 2, 3, 4]

Таким образом реализуется рекурсивный обход объекта для копирования всех его компонентов, причем реализуется полная копия, между которыми нет связи.

[Сестра сказала] Ну, я действительно не ожидала, что в простом задании столько ям! Я резюмирую от себя: присваивание common = на самом деле является только общей ссылкой; три метода неограниченного сегментирования, метод копирования словаря и встроенный список функций могут копировать объект верхнего уровня, а глубокое копирование может полностью реализовать объект верхнего уровня. объект Полная копия вниз. Поэтому, когда мы на самом деле его используем, мы должны учитывать эти огромные различия!

Напоследок добавим небольшое знание: проблемы сравнения, равенства и истинности в python.

L1 = [1,2,['A','B']]
L2 = [1,2,['A','B']]
L3 = L1
print(L1 == L2, L1 is L2)
print(L1 == L3, L1 is L3)

True False
True True

== проверяет равенство двух значений объекта, то есть рекурсивно сравнивает все внедренные объекты;

проверяет непротиворечивость двух объектов, то есть находятся ли они в одном и том же пространстве памяти.

проблема истинности

Python рассматривает любую пустую структуру данных как ложную, а любую непустую структуру данных как истинную.

Использование None обычно играет роль пустого заполнителя, который является ложным, когда оценивается истинное значение.

L = [None] * 10
print(L)

[None, None, None, None, None, None, None, None, None, None]

Встроенная функция bool может проверить, является ли объект истинным или ложным.

print(bool([1,2]))
print(bool(True))
print(bool(None))
print(bool('abcde'))

True
True
False
True

QR-код официального аккаунта: специалист по данным python: