Python Заметки
2.28K subscribers
60 photos
2 videos
2 files
215 links
Интересные заметки и обучающие материалы по Python

Контакт: @paulwinex

⚠️ Рекламу на канале не делаю!⚠️

Хештеги для поиска:
#tricks
#libs
#pep
#basic
#regex
#qt
#django
#2to3
#source
#offtop
Download Telegram
Все знают синтаксический сахар с операторами +=, -= и тд
x += 1

Где под капотом он превращается в
x = x + 1

Останется ли переменная х той же переменной после +=?
Конечно нет, это же неизменяемый тип
x = 1
print(id(x))
# 135373664533280
x += 1
print(id(x))
# 135373664533312


Теперь провернём тоже самое со списком
ls = [1, 2]
print(id(ls))
# 135373622585344
ls = ls + [3]
print(id(ls))
# 135373619036608

Ожидаемо работает так же, ведь мы создали новую переменную.
А теперь попробуем иначе:
ls = [1, 2]
print(id(ls))
# 135373622585344
ls += [3]
print(id(ls))
# 135373622585344
print(ls)
# [1, 2, 3]

И, внезапно, это работает не так как с int, со списками оператор += работает как extend()!
То же самое будет с *=, объект останется тем же.
ls = [1, 2]
print(id(ls))
# 135373622585344
ls *= 2
print(id(ls))
# 135373622585344
print(ls)
# [1, 2, 1, 2]

Следует помнить о такой важной разнице!
(Особенно на собесах 😉)

#tricks
👍121
Не запуская код определите, что покажет терминал если выполнить следующее:

_A__b = 'c'
class A:
def get(self):
return __b
print(A().get())


Ответ: Несмотря на то, что ваш IDE покажет ошибку, ошибки не будет. Распечатается "c"

Объяснение:

1. Mangling
За это отвечает механизм mangling - искажение имени. Так работают приватные атрибуты классов.
При создании атрибута по правилу: минимум 2 "_" в начале и максимум 1 "_" в конце" имя автоматически становится вида _{classname}{attr}
В нашем случае атрибутов класса не создается, но это не отменяет Mangling при обращении к другим объектам внутри класса.

2. Обращение к атрибуту
Когда внутри класса происходит обращение к любому объекту с именем по указанному выше правилу, его имя на уровне байт кода также преобразуется.

3. Поиск
Далее происходит поиск такой переменной по неймспейсам в порядке LEGB - Local, Enclosing, Global, Built-in.
И не трудно догадаться что мы находим нужный атрибут в Global, В итоге получаем результат!

Проверить можно так:
import dis
dis.dis(A.get)
# 4 RESUME 0
#
# 5 LOAD_GLOBAL 0 (_A__b)
# RETURN_VALUE

Либо удалите переменную _A__b и запустите еще раз, поулчите ошибку:
NameError: name '_A__b' is not defined


Как думаете, это норма или баг?

#tricks
5😢1