- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
import traceback
a = (1,2,[3,4])
try:
a[2] += [4,5]
except:
traceback.print_exc()
print(a)
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
+3
import traceback
a = (1,2,[3,4])
try:
a[2] += [4,5]
except:
traceback.print_exc()
print(a)
Traceback (most recent call last):
File "prog.py", line 5, in <module>
a[2] += [4,5]
TypeError: 'tuple' object does not support item assignment
(1, 2, [3, 4, 4, 5])
3_dar 13.06.2020 16:02 # 0
3_dar 13.06.2020 16:05 # 0
Сначала происходит +=, а потом пытается записать в tuple, но объект уже изменён.
nemyx 13.06.2020 16:19 # 0
Кортежи же (туплы) немутабельны, поэтому изменять их нельзя. Однако, список нельзя хранить в кортеже по значению, вместо него хранится ссылка. a[2] — это именно ссылка на список, а не сам список.
При изменении списка ссылка на него не меняется, потому что сам список меняется на месте. Поэтому списки, лежащие в кортеже, можно изменять.
Всё верно?
3_dar 13.06.2020 16:22 # +1
nemyx 13.06.2020 16:25 # 0
Точнее, она генерирует исключение, потому что кортежи иммутабельны.
Вот реальный пример без третьей строки:
https://ideone.com/4sxUjo
guest8 13.06.2020 16:29 # −999
nemyx 13.06.2020 16:30 # 0
gost 13.06.2020 16:26 # +1
«+=» в Путухе работает за счёт магического метода __iadd__(self, ...), который для списка делает «self.extend(...)» и возвращает self:
Далее интерпретатор пытается присвоить «новое» значение элементу кортежа и ожидаемо обламывается. А поскольку транзакций не завезли — исключение не откатывает изменения в списке.
В общем-то, налицо багор в рахитектуре, но то, как отбитые путухи в статье пытаются агрессивно отстоять эту хуйню («всё логично», «Но не странно ну вот вообще») — выглядит очень смешно. Один особенный ещё и сишку приплёл, лол.
jojaxon 13.06.2020 16:44 # 0
gost 13.06.2020 16:47 # 0
jojaxon 13.06.2020 16:50 # 0
gost 13.06.2020 17:00 # 0
getCells() возвращает ссылку на вектор, но при этом попортить внутренности хуя нельзя: ссылка константна, и std::vector::operator[]() тоже возвращает константную ссылку.
Для такого же уровня надёжности в каком-нибудь путухе, например, придётся возвращать копию массива, как и в ЙАЖЕ (впрочем, в последней, вроде как, можно какими-то ебанутыми кастами провернуть нечто похожее).
jojaxon 13.06.2020 16:55 # 0
guest8 13.06.2020 16:58 # −999
bormand 13.06.2020 17:00 # +1
jojaxon 13.06.2020 17:02 # 0
gost 13.06.2020 17:05 # 0
Или вообще как-нибудь так:
Это будет работать, если сам объект изначально non-const. А если он объявлен как const — UB.
UPD: Или ещё из очевидного:
guest8 13.06.2020 17:08 # −999
gost 13.06.2020 17:16 # 0
Как и сказал Борманд, если функция может читать любые данные, в которые кто-то (включая её саму) может что-то записать — она не потокобезопасна (ну, по-умолчанию, без синхронизации).
guest8 13.06.2020 17:48 # −999
gost 13.06.2020 17:55 # 0
guest8 13.06.2020 17:59 # −999
guest8 13.06.2020 18:15 # −999
bormand 13.06.2020 18:40 # 0
Т.е. это банальная защита от дурака чтобы случайно контракт не нарушить и не писнуть куда не надо, не более того.
guest8 13.06.2020 19:06 # −999
gost 13.06.2020 19:38 # 0
Казалось бы, выгледит потокобезопасно, но вот хуй:
Чтобы тип ссылки/метода обеспечивал потокобезопасность, компилятор должен гарантировать, что в любой момент времени во всех потоках на один и тот же объект существует либо ровно одна мутабельная ссылка, либо неограниченное количество иммутабельных. Казалось бы, при чём тут ржавчина?..
guest8 13.06.2020 20:00 # −999
gost 13.06.2020 20:02 # 0
Другие то методы могут быть не const. И даже если тебе передали конст ссылку на объект, это ещё не означает что у кого-то другого нет полноценной ссылки.
Т.е. это банальная защита от дурака чтобы случайно контракт не нарушить и не писнуть куда не надо, не более того.
bormand 13.06.2020 17:11 # 0
guest8 13.06.2020 20:38 # −999
KOPOHABuPYC 13.06.2020 22:27 # 0
Ах, как же омерзительны порой людские пороки... Один страшнее другого.
gost 14.06.2020 14:50 # 0
jojaxon 14.06.2020 15:55 # +1
gost 13.06.2020 16:30 # +1
nemyx 13.06.2020 18:50 # 0
https://ideone.com/IUfM9r
guest8 13.06.2020 19:04 # −999
nemyx 13.06.2020 19:08 # +1
nemyx 13.06.2020 19:40 # 0
Я решил, что семантичнее будет эмулировать питоньи туплы пэхапэшными классами, ибо у классов фиксированное количество полей, в отличие от массивов, размер которых динамичен.
Оказалось, что не так просто создать класс с нумерными полями. На $0, ${0}, ${'0'} парсер обламывается, хотя обычные переменные (не поля класса) можно сделать нумерными. При этом через десериализацию нумерные поля легко создаются.
Есть вариант через каст из массива ((object)[1,2,[3,4]]), но тогда не работает функция array_push, потому что [3,4] в этом случае почему-то не остаётся массивом, а конвертируется в экземпляр класса, у которого какие-то методы массива не определены.
А с именованными полями всё работает. В «PHP7» даже анонимные классы завезли:
guest8 13.06.2020 22:38 # −999
nemyx 13.06.2020 23:02 # 0
3_dar 14.06.2020 00:57 # 0
Так создай stdClass через каст, а потом присвой массив 2-му элементу.
nemyx 14.06.2020 00:58 # 0
jojaxon 14.06.2020 05:13 # 0