[Python, Программирование, Проектирование и рефакторинг] Python: неочевидное в очевидном
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
ВведениеИзучение любого языка - очень долгий процесс, в ходе которого могут возникать ситуации, когда очевидные с виду вещи ведут себя странно. Даже спустя много лет изучения языка не все и не всегда могут с уверенностью сказать “да, я знаю этот на 100%, несите следующий”.Python - один из самых популярных языков программирования на сегодняшний день, но и он имеет ряд своих нюансов, которые на протяжении многих лет изменялись, оптимизировались и теперь ведут себя немного не так, как это может показаться, глядя на строчки незамысловатого кода.Немного строкМетод is для сравнения строкРассмотрим несколько примеров, в которых работа со строками может быть не такой гладкой. Для начала необходимо создать файл (пусть будет test.py), и в нем реализовать функцию для тестирования работы строк:
def test_str():
# пример 1
a = "hello"
b = "hello"
print("Пример 1:", a is b)
# пример 2
c = "hell"
print("Пример 2:", c+"o" is a)
# пример 3
a = "hello"
b = "hello"
print("Пример 3:", a + “!” is b + “!”)
# пример 4
a, b = "hello!", "hello!"
print("Пример 4:" ,a is b)
# пример 5
a = "привет"
b = "привет"
print("Пример 5:", a is b)
# пример 6
a = "!"
b = "!"
print("Пример 6:", a is b)
test_str()
После запуска кода вывод будет таким:
Пример 1: True
Пример 2: False
Пример 3: False
Пример 4: True
Пример 5: True
Пример 6: True
В примере 1 вроде всё логично, есть 2 строки, мы проверяем, является ли одна строка другой при помощи метода is (а именно, ссылаются ли две переменные на одну строку). Так как значения обеих строки равны, то и они (по идеи) должны быть равны. Но в примере 2 видно, что сравниваются 2 одинаковые строки (ведь “hell” + “o” даст в итоге “hello”), но по итогу is вернул False.Python оптимизирует работу со строками, используя метод интернирования, то есть для некоторых неизменяемых объектов python хранит только 1 экземпляр в памяти, как следствие, если в 2х переменных хранятся одинаковые строки, то они будут ссылаться на одну ячейку в памяти. Но это верно лишь отчасти.
При запуске программы интернирование происходит до момента её выполнения, именно поэтому в случае примера 2 строка, полученная при помощи конкатенации “hell” и “o” не была интернирована. Как следствие, во время выполнения программы строка “hello” (переменной a) и строка “hello” (полученная при помощи c + “o”) не будут ссылаться на один объект в памяти. Работу python можно проверить при помощи:
import dis
def test_dis():
a = "hello"
b = "hello"
print("Пример 1:", a is b)
c = "hello"
d = "hell"
print("Пример 2:", d+"o" is c)
dis.dis(test_dis)
Вывод:
38 0 LOAD_CONST 1 ('hello')
2 STORE_FAST 0 (a)
39 4 LOAD_CONST 1 ('hello')
6 STORE_FAST 1 (b)
40 8 LOAD_GLOBAL 0 (print)
10 LOAD_CONST 2 ('Пример 1:')
12 LOAD_FAST 0 (a)
14 LOAD_FAST 1 (b)
16 IS_OP 0
18 CALL_FUNCTION 2
20 POP_TOP
42 22 LOAD_CONST 1 ('hello')
24 STORE_FAST 2 (c)
43 26 LOAD_CONST 3 ('hell')
28 STORE_FAST 3 (d)
44 30 LOAD_GLOBAL 0 (print)
32 LOAD_CONST 4 ('Пример 2:')
34 LOAD_FAST 3 (d)
36 LOAD_CONST 5 ('o')
38 BINARY_ADD
40 LOAD_FAST 2 (c)
42 IS_OP 0
44 CALL_FUNCTION 2
46 POP_TOP
48 LOAD_CONST 0 (None)
50 RETURN_VALUE
Как видно, в строке 0 и 4 в переменные a и b ссылаются на константные значения “hello”, а переменная d (в строке 26) ссылается на значение hell, после чего в 38 строке идет сложение значений из переменной d и строки “o”, и данное значение не берется из памяти (как в случае с переменными a и b), а получается новая строка с новым id.Если же рассмотреть пример с вводом данных с клавиатуры (или из любого другого источника), то можно заметить следующий результат:
while True:
a = input("Введите a: ")
b = input("Введите b: ")
print(a, b, a is b, id(a), id(b))
Вывод:
Введите a: hello
Введите b: hello
hello hello False 2437519007408 2437519445104
Введите a: !
Введите b: !
! ! True 2437486790320 2437486790320
Введите a: W
Введите b: W
W W True 2437484664176 2437484664176
Введите a: д
Введите b: д
д д False 2713563632704 2713563632624
Все ASCII символы (ASCII строки длины 1 и 0) содержатся в python в единственном экземпляре изначально, поэтому вводя строку длиной 1 (или 0) можно быть уверенным, что это один тот же элемент в памяти, но для каждой не ASCII строки (либо строки с длиной больше 1) выделяется новое место в памяти в ходе выполнения программы.Такая особенность хранения строк в Python позволяет экономить память, однако надо быть аккуратными при работе со строками, а именно, при сравнении строк при помощи метода is.Конкатенация строкЕще один пример. Конкатенирование строк в Python:
def test_str2():
import time
s1 = "Привет"
s2 = "Всем"
s3 = ","
s4 = "Кто"
s5 = "Это"
s6 = "Читает"
t = time.time()
for _ in range(1000000):
s = s1 + " " + s2 + " " + s3 + " " + s4 + " " + s5 + " " + s6
r = time.time() - t
print("Время на +: ", r)
t = time.time()
for _ in range(1000000):
s = " ".join([s1, s2, s3, s4, s5, s6])
r = time.time() - t
print("Время на join: ", r)
t = time.time()
for _ in range(1000000):
s = "{} {} {} {} {} {}".format(s1, s2, s3, s4, s5, s6)
r = time.time() - t
print("Время на format: ", r)
t = time.time()
for _ in range(1000000):
s = "%s %s %s %s %s %s" % (s1, s2, s3, s4, s5, s6)
r = time.time() - t
print("Время на %: ", r)
t = time.time()
for _ in range(1000000):
s = f"{s1} {s2} {s3} {s4} {s5} {s6}"
r = time.time() - t
print("Время на f-string: ", r)
test_str2()
Вывод:
Время на +: 0.601959228515625
Время на join: 0.3228156566619873
Время на format: 0.6226434707641602
Время на %: 0.49173593521118164
Время на f-string: 0.28386688232421875
F-string было введено в Python 3.6. Хотя существует несколько способов объединять строки, многие не задаются вопросов “зачем столько всякого?”, считая, что это всего лишь украшения языка для удобства пользования (ведь запись f”{s1} {s2}...” более понятна, чем s1 + “ ” + s2+ … + sn). Но разные методы работы со строкам расходуют разный объем памяти и времени, f-string был введен с целью ускорить работу со строками.Проведя dis.dis() для данного метода, можно заметить, что разные методы конкатенации вызывают разные состояния, которые в свою очередь различаются по реализации.Для “+” выполняются следующие действия:
140 52 LOAD_FAST 1 (s1)
54 LOAD_CONST 9 (' ')
56 BINARY_ADD
58 LOAD_FAST 2 (s2)
60 BINARY_ADD
62 LOAD_CONST 9 (' ')
64 BINARY_ADD
66 LOAD_FAST 3 (s3)
68 BINARY_ADD
70 LOAD_CONST 9 (' ')
72 BINARY_ADD
74 LOAD_FAST 4 (s4)
76 BINARY_ADD
78 LOAD_CONST 9 (' ')
80 BINARY_ADD
82 LOAD_FAST 5 (s5)
84 BINARY_ADD
86 LOAD_CONST 9 (' ')
88 BINARY_ADD
90 LOAD_FAST 6 (s6)
92 BINARY_ADD
94 STORE_FAST 9 (s)
Как видно, каждый раз вызывается состояние BINARY_ADD (см. подробнее оф. гитхаб cpython: строка case TARGET(BINARY_ADD)). Для метода “”.join():
140 LOAD_CONST 9 (' ')
142 LOAD_METHOD 3 (join)
144 LOAD_FAST 1 (s1)
146 LOAD_FAST 2 (s2)
148 LOAD_FAST 3 (s3)
150 LOAD_FAST 4 (s4)
152 LOAD_FAST 5 (s5)
154 LOAD_FAST 6 (s6)
156 BUILD_LIST 6
158 CALL_METHOD 1
160 STORE_FAST 9 (s)
Для format:
206 LOAD_CONST 12 ('{} {} {} {} {} {}')
208 LOAD_METHOD 4 (format)
210 LOAD_FAST 1 (s1)
212 LOAD_FAST 2 (s2)
214 LOAD_FAST 3 (s3)
216 LOAD_FAST 4 (s4)
218 LOAD_FAST 5 (s5)
220 LOAD_FAST 6 (s6)
222 CALL_METHOD 6
224 STORE_FAST 9 (s)
Для %s:
270 LOAD_CONST 14 ('%s %s %s %s %s %s')
272 LOAD_FAST 1 (s1)
274 LOAD_FAST 2 (s2)
276 LOAD_FAST 3 (s3)
278 LOAD_FAST 4 (s4)
280 LOAD_FAST 5 (s5)
282 LOAD_FAST 6 (s6)
284 BUILD_TUPLE 6
286 BINARY_MODULO
288 STORE_FAST 9 (s)
290 EXTENDED_ARG 1
Для f-string:
336 LOAD_FAST 1 (s1)
338 FORMAT_VALUE 0
340 LOAD_CONST 9 (' ')
342 LOAD_FAST 2 (s2)
344 FORMAT_VALUE 0
346 LOAD_CONST 9 (' ')
348 LOAD_FAST 3 (s3)
350 FORMAT_VALUE 0
352 LOAD_CONST 9 (' ')
354 LOAD_FAST 4 (s4)
356 FORMAT_VALUE 0
358 LOAD_CONST 9 (' ')
360 LOAD_FAST 5 (s5)
362 FORMAT_VALUE 0
364 LOAD_CONST 9 (' ')
366 LOAD_FAST 6 (s6)
368 FORMAT_VALUE 0
370 BUILD_STRING 11
372 STORE_FAST 9 (s)
374 EXTENDED_ARG 1
Сравнение объектов Рассмотрим небольшой пример сравнения двух экземпляров классов:
def test_class():
class my_class():
pass
a, b = my_class(), my_class()
print(a == b)
print(a is b)
print(id(a) == id(b))
print(hash(a) == hash(b))
test_class()
Вывод:
False
False
False
False
Всё замечательно. Теперь посмотрим на другой пример:
def test_class2():
class my_class():
pass
print(my_class() == my_class())
print(my_class() is my_class())
print(hash(my_class()) == hash(my_class()))
print(id(my_class()) == id(my_class()))
test_class()
Вывод:
False
False
True
True
Что-то пошло не так. Вроде так же создаются 2 экземпляра класса, но при этом вывод показывает, что hash и id этих экземпляров одинаковы, но is показывает, что это получаются разные объекты. Рассмотрим еще пример:
def test_class3():
class my_class():
pass
print(my_class() == my_class())
print(my_class() is my_class())
print(hash(a:=my_class()) == hash(b:=my_class()))
print(id(c:=my_class()) == id(d:=my_class()))
test_class3()
Вывод:
False
False
False
False
Всё опять встало на свои места. Дополним немного my_class во всех примерах:
class my_class():
def __init__(self):
print("__init__")
def __del__(self):
print("__del__")
Как это работает? Когда создается экземпляр класса, он получает свой уникальный id, но как только у него вызывается метод __del__, тот самый id уже перестает принадлежать этому объекту, и точно такой же id может быть присвоен другому объекту, например:
class my_class():
pass
a = my_class()
print(id(a))
>>> 2082631974720
del a
b = my_class()
print(id(b))
>>> 2082631974720
Когда python создает объект класса, как в случае 1 (в методе test_class), то на этот объект ссылается переменная, следовательно, этот объект хранится в памяти до тех пор, пока на него что-то ссылается. В примере 3 аналогично, a := my_class() и b := my_class() - “моржовый” оператор := создает переменную a, которая во время выполнения функции print живёт и ссылается на объект, а переменная b ссылается уже на другой объект, так как у объекта в a:=my_class() не был вызван метод __del__.Пример 2 самый интересный. Когда вызывается id(my_class()), то происходит следующее: создается экземпляр класса my_class, этот только что созданный объект передается функции id, которая берёт id объекта, затем объект уничтожается и вызывается часть id(my_class()), стоящая справа от ==. Опять создается my_class (который, как мы определили чуть выше, будет иметь такой же id, как был у предыдущего my_class(), который уже не существует), и правая функция id получается значение id этого объекта. Так получается, что id слева и справа от == получают идентификаторы своих объектов в то время, когда физически существует только один из этих объектов, следовательно id, полученное слева будет таким же, как id полученное справа.Назревает вопрос: почему метод is в примере 2 выдает False, id объектов должны же быть одинаковы, значит, они ссылаются на один объект? Чуть выше был изменён класс my_class. Для наглядности можно запустить пример 2 еще раз. Получим такой результат:
__init__
__init__
__del__
__del__
False
__init__
__init__
__del__
__del__
False
__init__
__del__
__init__
__del__
True
__init__
__del__
__init__
__del__
True
Когда выполнялся print с hash или id, видно, что по отдельности сначала вызывается конструктор, потом деструктор одного объекта, а потом конструктор и деструктор другого объекта, именно после того, как функции hash или id завершали свои действия, вызывался метод __del__ и создавался новый объект. В примере с is видно, что сначала создались оба экземпляра класса, а только потом вызывался метод __del__ у каждого из них. Это дает понять, что метод is выполнялся таким образом, что сначала создавались оба объекта my_class(), потом они сравнивались, а только лишь после выполнения is они оба удалялись (т.е. два экземпляра my_class жили в одно время и физически не могли иметь 2 одинаковых id).И еще немногоИзменение данных внутри кортежаСоздадим кортеж, который содержит в себе список, и попробуем расширить этот список, добавив новые элементы:
def test_list():
a = ([], 0)
a[0].extend([1])
print("Применили extend: ", a)
a[0].append(2)
print("Применили append: ", a)
a[0].insert(0,0)
print("Применили insert: ", a)
try:
a[0] += [4]
print("Применяем +=: ", a)
except Exception as e:
print(e)
print("Итоговый кортеж:", a)
test_list()
Вывод:
Применили extend: ([1], 0)
Применили append: ([1, 2], 0)
Применили insert: ([0, 1, 2], 0)
'tuple' object does not support item assignment
Итоговый кортеж: ([0, 1, 2, 4], 0)
Очень забавная ситуация, кортеж выкинул ошибку, однако список все равно был расширен. Аналогично будет себя вести пример со словарями ( оператор |= - был добавлен в версии 3.9).
def test_dicts():
a = ({}, 0)
a[0]["cat"] = 100
print("Изменяем словарь: ", a)
a[0].update([("dog", 200)])
print("Применили update: ", a)
a[0].update({"bird": 50})
print("Применили update: ", a)
try:
a[0] |= {"lion": 200}
print("Применили |=: ", a)
except Exception as e:
print(e)
print("Итоговый словарь: ", a)
test_dicts()
Вывод:
Изменяем словарь: ({'cat': 100}, 0)
Применили update: ({'cat': 100, 'dog': 200}, 0)
Применили update: ({'cat': 100, 'dog': 200, 'bird': 50}, 0)
'tuple' object does not support item assignment
Итоговый словарь: ({'cat': 100, 'dog': 200, 'bird': 50, 'lion': 200}, 0)
Создание таблицыДопустим, необходимо создать таблицу (матрицу, двумерный массив) с данными и поменять в нём первый элемент:
def test_list_2():
row = ["_"] * 3
table = [row] * 3
print("Создали таблицу:\n",table )
table[0][0] = "X"
print("Изменили первый элемент:\n",table )
test_list_2()
Вывод:
Создали таблицу:
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
Изменили первый элемент:
[['X', '_', '_'], ['X', '_', '_'], ['X', '_', '_']]
Поменялся не только самый первый элемент таблицы, но и первые элементы в каждой строке. Если использовать инициализацию таблицы путем умножения одного списка, то каждая строка таблицы будет содержать один и тот же список (ссылаться на один список row).
Убедиться в этом можно, выполнив следующий код:
for table_row in table:
print(id(table_row))
Вывод:
1707508645824
1707508645824
1707508645824
Метод allНемного о методе all:
def test_all():
print(all([]))
print(all([[]]))
print(all([[[]]]))
print(all([[[[]]]]))
test_all()
Вывод:
True
False
True
True
Почему так? all([]) - по определению выдаст True. Ситуация с all([[]]) объясняется тем, что для каждый элемент во внешнем списке приводится к булевскому значению (как известно, к False приводятся: ноль, пустая строка, пустой список и др.), поэтому внешний список содержит [], который интерпретируется как False. В all([[[]]]), внешний список содержит список, в котором есть список, а список с 1 элементов уже интерпретируется, как True, то есть all не проверяет вложенность списков.ВыводВсе эти примеры довольно очевидны для опытного программиста, но иногда могут вводить в ступор, особенно, если приходится читать чужой код и пытаться найти в нём ошибку. Такого рода ошибки порождают массу проблем, если плохо разбираться в нюансах работы языка. Поэтому иногда стоит читать и изучать чужой код, изучать статьи по языку и читать документацию к работе методов, чтобы видеть и понимать, какие сюрпризы может преподнести язык. И не стоит забывать, используя два разных языка и описав в них одинаковые конструкции, они могут вести себя совершенно по-разному, потому что внутренняя реализация у каждого языка своя.P.s. всё тестировал на Python 3.9 в стандартной IDLE.
===========
Источник:
habr.com
===========
Похожие новости:
- [Разработка веб-сайтов, Работа с видео, Программирование, Видеоконференцсвязь] WebRTC screen-sharing with authorization and other benefits
- [Разработка веб-сайтов, Работа с видео, Программирование, Видеоконференцсвязь] WebRTC скриншаринг с авторизацией и плюшками
- [Python, Big Data, Машинное обучение] ML-обработка результатов голосований Госдумы (2016-2021)
- [Разработка веб-сайтов, Программирование, GitHub, Изучение языков, Natural Language Processing] Написал приложение для создания параллельных книг, которое вас удивит
- [Разработка веб-сайтов, JavaScript, Node.JS, API, TypeScript] Декларативный API на Next.JS — реальность?
- [Python, Программирование, Работа с 3D-графикой, Машинное обучение] Пристальный взгляд на код из лучшего доклада конференции по компьютерному зрению и распознаванию образов 2021 — GIRAFFE (перевод)
- [Python, MongoDB, Голосовые интерфейсы] Голосовой дневник на python с распознаванием голоса и сохранением в Mongo DB
- [Программирование, Assembler, Отладка] Assembler – Урок 0: Установка компилятора и запуск первой программы через DOSBox
- [Системное программирование, D, Программирование микроконтроллеров] За рулем с D (перевод)
- [Программирование] Обычное двоичное дерево для тестового задания
Теги для поиска: #_python, #_programmirovanie (Программирование), #_proektirovanie_i_refaktoring (Проектирование и рефакторинг), #_python, #_bagi (баги), #_programmirovanie (программирование), #_njuansy (нюансы), #_refaktoring (рефакторинг), #_python, #_programmirovanie (
Программирование
), #_proektirovanie_i_refaktoring (
Проектирование и рефакторинг
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:16
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
ВведениеИзучение любого языка - очень долгий процесс, в ходе которого могут возникать ситуации, когда очевидные с виду вещи ведут себя странно. Даже спустя много лет изучения языка не все и не всегда могут с уверенностью сказать “да, я знаю этот на 100%, несите следующий”.Python - один из самых популярных языков программирования на сегодняшний день, но и он имеет ряд своих нюансов, которые на протяжении многих лет изменялись, оптимизировались и теперь ведут себя немного не так, как это может показаться, глядя на строчки незамысловатого кода.Немного строкМетод is для сравнения строкРассмотрим несколько примеров, в которых работа со строками может быть не такой гладкой. Для начала необходимо создать файл (пусть будет test.py), и в нем реализовать функцию для тестирования работы строк: def test_str():
# пример 1 a = "hello" b = "hello" print("Пример 1:", a is b) # пример 2 c = "hell" print("Пример 2:", c+"o" is a) # пример 3 a = "hello" b = "hello" print("Пример 3:", a + “!” is b + “!”) # пример 4 a, b = "hello!", "hello!" print("Пример 4:" ,a is b) # пример 5 a = "привет" b = "привет" print("Пример 5:", a is b) # пример 6 a = "!" b = "!" print("Пример 6:", a is b) test_str() Пример 1: True
Пример 2: False Пример 3: False Пример 4: True Пример 5: True Пример 6: True При запуске программы интернирование происходит до момента её выполнения, именно поэтому в случае примера 2 строка, полученная при помощи конкатенации “hell” и “o” не была интернирована. Как следствие, во время выполнения программы строка “hello” (переменной a) и строка “hello” (полученная при помощи c + “o”) не будут ссылаться на один объект в памяти. Работу python можно проверить при помощи: import dis
def test_dis(): a = "hello" b = "hello" print("Пример 1:", a is b) c = "hello" d = "hell" print("Пример 2:", d+"o" is c) dis.dis(test_dis) 38 0 LOAD_CONST 1 ('hello')
2 STORE_FAST 0 (a) 39 4 LOAD_CONST 1 ('hello') 6 STORE_FAST 1 (b) 40 8 LOAD_GLOBAL 0 (print) 10 LOAD_CONST 2 ('Пример 1:') 12 LOAD_FAST 0 (a) 14 LOAD_FAST 1 (b) 16 IS_OP 0 18 CALL_FUNCTION 2 20 POP_TOP 42 22 LOAD_CONST 1 ('hello') 24 STORE_FAST 2 (c) 43 26 LOAD_CONST 3 ('hell') 28 STORE_FAST 3 (d) 44 30 LOAD_GLOBAL 0 (print) 32 LOAD_CONST 4 ('Пример 2:') 34 LOAD_FAST 3 (d) 36 LOAD_CONST 5 ('o') 38 BINARY_ADD 40 LOAD_FAST 2 (c) 42 IS_OP 0 44 CALL_FUNCTION 2 46 POP_TOP 48 LOAD_CONST 0 (None) 50 RETURN_VALUE while True:
a = input("Введите a: ") b = input("Введите b: ") print(a, b, a is b, id(a), id(b)) Введите a: hello
Введите b: hello hello hello False 2437519007408 2437519445104 Введите a: ! Введите b: ! ! ! True 2437486790320 2437486790320 Введите a: W Введите b: W W W True 2437484664176 2437484664176 Введите a: д Введите b: д д д False 2713563632704 2713563632624 def test_str2():
import time s1 = "Привет" s2 = "Всем" s3 = "," s4 = "Кто" s5 = "Это" s6 = "Читает" t = time.time() for _ in range(1000000): s = s1 + " " + s2 + " " + s3 + " " + s4 + " " + s5 + " " + s6 r = time.time() - t print("Время на +: ", r) t = time.time() for _ in range(1000000): s = " ".join([s1, s2, s3, s4, s5, s6]) r = time.time() - t print("Время на join: ", r) t = time.time() for _ in range(1000000): s = "{} {} {} {} {} {}".format(s1, s2, s3, s4, s5, s6) r = time.time() - t print("Время на format: ", r) t = time.time() for _ in range(1000000): s = "%s %s %s %s %s %s" % (s1, s2, s3, s4, s5, s6) r = time.time() - t print("Время на %: ", r) t = time.time() for _ in range(1000000): s = f"{s1} {s2} {s3} {s4} {s5} {s6}" r = time.time() - t print("Время на f-string: ", r) test_str2() Время на +: 0.601959228515625
Время на join: 0.3228156566619873 Время на format: 0.6226434707641602 Время на %: 0.49173593521118164 Время на f-string: 0.28386688232421875 140 52 LOAD_FAST 1 (s1)
54 LOAD_CONST 9 (' ') 56 BINARY_ADD 58 LOAD_FAST 2 (s2) 60 BINARY_ADD 62 LOAD_CONST 9 (' ') 64 BINARY_ADD 66 LOAD_FAST 3 (s3) 68 BINARY_ADD 70 LOAD_CONST 9 (' ') 72 BINARY_ADD 74 LOAD_FAST 4 (s4) 76 BINARY_ADD 78 LOAD_CONST 9 (' ') 80 BINARY_ADD 82 LOAD_FAST 5 (s5) 84 BINARY_ADD 86 LOAD_CONST 9 (' ') 88 BINARY_ADD 90 LOAD_FAST 6 (s6) 92 BINARY_ADD 94 STORE_FAST 9 (s) 140 LOAD_CONST 9 (' ')
142 LOAD_METHOD 3 (join) 144 LOAD_FAST 1 (s1) 146 LOAD_FAST 2 (s2) 148 LOAD_FAST 3 (s3) 150 LOAD_FAST 4 (s4) 152 LOAD_FAST 5 (s5) 154 LOAD_FAST 6 (s6) 156 BUILD_LIST 6 158 CALL_METHOD 1 160 STORE_FAST 9 (s) 206 LOAD_CONST 12 ('{} {} {} {} {} {}')
208 LOAD_METHOD 4 (format) 210 LOAD_FAST 1 (s1) 212 LOAD_FAST 2 (s2) 214 LOAD_FAST 3 (s3) 216 LOAD_FAST 4 (s4) 218 LOAD_FAST 5 (s5) 220 LOAD_FAST 6 (s6) 222 CALL_METHOD 6 224 STORE_FAST 9 (s) 270 LOAD_CONST 14 ('%s %s %s %s %s %s')
272 LOAD_FAST 1 (s1) 274 LOAD_FAST 2 (s2) 276 LOAD_FAST 3 (s3) 278 LOAD_FAST 4 (s4) 280 LOAD_FAST 5 (s5) 282 LOAD_FAST 6 (s6) 284 BUILD_TUPLE 6 286 BINARY_MODULO 288 STORE_FAST 9 (s) 290 EXTENDED_ARG 1 336 LOAD_FAST 1 (s1)
338 FORMAT_VALUE 0 340 LOAD_CONST 9 (' ') 342 LOAD_FAST 2 (s2) 344 FORMAT_VALUE 0 346 LOAD_CONST 9 (' ') 348 LOAD_FAST 3 (s3) 350 FORMAT_VALUE 0 352 LOAD_CONST 9 (' ') 354 LOAD_FAST 4 (s4) 356 FORMAT_VALUE 0 358 LOAD_CONST 9 (' ') 360 LOAD_FAST 5 (s5) 362 FORMAT_VALUE 0 364 LOAD_CONST 9 (' ') 366 LOAD_FAST 6 (s6) 368 FORMAT_VALUE 0 370 BUILD_STRING 11 372 STORE_FAST 9 (s) 374 EXTENDED_ARG 1 def test_class():
class my_class(): pass a, b = my_class(), my_class() print(a == b) print(a is b) print(id(a) == id(b)) print(hash(a) == hash(b)) test_class() False
False False False def test_class2():
class my_class(): pass print(my_class() == my_class()) print(my_class() is my_class()) print(hash(my_class()) == hash(my_class())) print(id(my_class()) == id(my_class())) test_class() False
False True True def test_class3():
class my_class(): pass print(my_class() == my_class()) print(my_class() is my_class()) print(hash(a:=my_class()) == hash(b:=my_class())) print(id(c:=my_class()) == id(d:=my_class())) test_class3() False
False False False class my_class():
def __init__(self): print("__init__") def __del__(self): print("__del__") class my_class():
pass a = my_class() print(id(a)) >>> 2082631974720 del a b = my_class() print(id(b)) >>> 2082631974720 __init__
__init__ __del__ __del__ False __init__ __init__ __del__ __del__ False __init__ __del__ __init__ __del__ True __init__ __del__ __init__ __del__ True def test_list():
a = ([], 0) a[0].extend([1]) print("Применили extend: ", a) a[0].append(2) print("Применили append: ", a) a[0].insert(0,0) print("Применили insert: ", a) try: a[0] += [4] print("Применяем +=: ", a) except Exception as e: print(e) print("Итоговый кортеж:", a) test_list() Применили extend: ([1], 0)
Применили append: ([1, 2], 0) Применили insert: ([0, 1, 2], 0) 'tuple' object does not support item assignment Итоговый кортеж: ([0, 1, 2, 4], 0) def test_dicts():
a = ({}, 0) a[0]["cat"] = 100 print("Изменяем словарь: ", a) a[0].update([("dog", 200)]) print("Применили update: ", a) a[0].update({"bird": 50}) print("Применили update: ", a) try: a[0] |= {"lion": 200} print("Применили |=: ", a) except Exception as e: print(e) print("Итоговый словарь: ", a) test_dicts() Изменяем словарь: ({'cat': 100}, 0)
Применили update: ({'cat': 100, 'dog': 200}, 0) Применили update: ({'cat': 100, 'dog': 200, 'bird': 50}, 0) 'tuple' object does not support item assignment Итоговый словарь: ({'cat': 100, 'dog': 200, 'bird': 50, 'lion': 200}, 0) def test_list_2():
row = ["_"] * 3 table = [row] * 3 print("Создали таблицу:\n",table ) table[0][0] = "X" print("Изменили первый элемент:\n",table ) test_list_2() Создали таблицу:
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] Изменили первый элемент: [['X', '_', '_'], ['X', '_', '_'], ['X', '_', '_']] Убедиться в этом можно, выполнив следующий код: for table_row in table:
print(id(table_row)) 1707508645824
1707508645824 1707508645824 def test_all():
print(all([])) print(all([[]])) print(all([[[]]])) print(all([[[[]]]])) test_all() True
False True True =========== Источник: habr.com =========== Похожие новости:
Программирование ), #_proektirovanie_i_refaktoring ( Проектирование и рефакторинг ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:16
Часовой пояс: UTC + 5