Forwarded from Коробка с питоном
Решил расширить канал ещё одной тематикой - занимательными задачками.
Пока что буду писать про те, которые встречались на тех. собеседованиях.Они не всегда будут адекватные, но что уж есть :)
А начнём, как полагается с классики. Надо объяснить следующее поведение:
Вопрос в том, что здесь творится с ссылками. Разберём самую первую часть. Пробуем получить id объектов:
На вопрос, почему у них одинаковые идентификаторы ответит деталь реализации PyLong_FromLong(для искушенных читать можно читать отсюда ) , которая указывает, что интерпретатор хранит массив целочисленных объектов для всех чисел в диапазоне от -5 до 256. Поэтому, когда мы создаем переменную с числом в этом диапазоне он просто отдает ссылку на уже существующий объект.
Микрооптимизация, при чём очень важная - так уж получилось что числа из этого диапазона используются чаще всего.
В Java есть похожая оптимизация, там такой диапазон составляет от -128 до 127, но есть нюансы .
Второй вопрос отпадает сам собой (будут разные ссылки), но что будет если мы создадим файл с следующим содержимым и запустим его:
А вот это уже нюанс работы нашего REPL.
Каждая написанная нами строка в нём разбирается отдельно. Но при запуске через файл Python имеет возможность применить дополнительные оптимизации для констант, так как он видит сразу весь код - в этом и различие.
А какие ещё неочевидные моменты вы знаете с REPL или int'ами? Пишите в комменты, обсудим :)
#std #задачки
Пока что буду писать про те, которые встречались на тех. собеседованиях.
А начнём, как полагается с классики. Надо объяснить следующее поведение:
>>> a = 256
>>> b = 256
>>> a is b
True # ???
>>> a = 257
>>> b = 257
>>> a is b
False # ???
Вопрос в том, что здесь творится с ссылками. Разберём самую первую часть. Пробуем получить id объектов:
>>> a = 256
>>> b = 256
>>> id(a), id(b)
(2214170730704, 2214170730704)
На вопрос, почему у них одинаковые идентификаторы ответит деталь реализации PyLong_FromLong
Микрооптимизация, при чём очень важная - так уж получилось что числа из этого диапазона используются чаще всего.
Второй вопрос отпадает сам собой (будут разные ссылки), но что будет если мы создадим файл с следующим содержимым и запустим его:
a = 257
b = 257
print(a is b) # True
А вот это уже нюанс работы нашего REPL.
Каждая написанная нами строка в нём разбирается отдельно. Но при запуске через файл Python имеет возможность применить дополнительные оптимизации для констант, так как он видит сразу весь код - в этом и различие.
А какие ещё неочевидные моменты вы знаете с REPL или int'ами? Пишите в комменты, обсудим :)
#std #задачки
Python documentation
Integer Objects
All integers are implemented as “long” integer objects of arbitrary size. On error, most PyLong_As* APIs return(return type)-1 which cannot be distinguished from a number. Use PyErr_Occurred() to d...
Forwarded from Коробка с питоном
Сегодня у нас простенькая задачка, а то пятница, все отдыхать хотят, я понимаю.
Есть следующий код:
Вопрос - что вернется при вызове(ну не просто так же мы собрались, верно?) , но почему?
Ответ, как обычно, есть в документации. Возвращаемое функцией значение определяется последним выполненным return.
Вторым важным аспектом является то, что finally исполняется всегда, поэтому мы и получаем его return.
#std #задачки
Есть следующий код:
def test():
try:
return 1
finally:
return 2
Вопрос - что вернется при вызове
test()
? Все и так на этом моменте понимают, что вернётся 2 Ответ, как обычно, есть в документации. Возвращаемое функцией значение определяется последним выполненным return.
Вторым важным аспектом является то, что finally исполняется всегда, поэтому мы и получаем его return.
raise
, кстати, тоже работать не будет:def test():
try:
raise ValueError()
finally:
return 3
test() # 3
#std #задачки
Python documentation
8. Errors and Exceptions
Until now error messages haven’t been more than mentioned, but if you have tried out the examples you have probably seen some. There are (at least) two distinguishable kinds of errors: syntax error...
Forwarded from Коробка с питоном
Создание временных файлов
В процессе написания скрипта может потребоваться создание временных файлов, которые будут удалены автоматически после завершения работы скрипта или обработки файла.
Это может быть полезно по разным причинам - при обработке больших данных (которые не вместятся в буфер) или при проведении сложных операций (например, можно создать временный файл и натравить на него ffmpeg).
Для решения этих проблем в Python есть модуль
В процессе написания скрипта может потребоваться создание временных файлов, которые будут удалены автоматически после завершения работы скрипта или обработки файла.
Это может быть полезно по разным причинам - при обработке больших данных (которые не вместятся в буфер) или при проведении сложных операций (например, можно создать временный файл и натравить на него ffmpeg).
Для решения этих проблем в Python есть модуль
tempfile
. Нас интересует 2 функции - это TemporaryFile
и NamedTemporaryFile
.TemporaryFile
позволяет создать безымянный временный файл. Вот так можно создать временный текстовой файл, открыть его на запись и чтение (за это отвечает первый аргумент "w+t"
, подробнее можно прочитать здесь):from tempfile import TemporaryFile
with TemporaryFile("w+t") as t:
t.write("Hello, boxwithpython!")
t.seek(0)
data = t.read()
NamedTemporaryFile
используется для более продвинутых сценариев, так как он создает файл с именем, поэтому мы можем получить путь к нему и использовать его для дальнейших целей:from tempfile import
NamedTemporaryFile
with NamedTemporaryFile("w+t") as t:#std
t.write("Hello, boxwithpython!")
print(t.name) # /tmp/tmpljhsktjt
Forwarded from Коробка с питоном
Про __slots__
Python, аналогично другим динамическим языкам, таким как JavaScript, предоставляет возможность манипулирования объектами в рантайме, в том числе позволяет добавлять, изменять и удалять атрибуты. Цена этого – понижение скорости доступа к атрибутам и дополнительные расходы памяти.
Такое поведение нужно не всегда. Бывают случаи, когда мы точно знаем, какие атрибуты будут у наших экземпляров классов. Или же мы хотим ограничить добавление новых атрибутов. Именно для этого и существует
Слоты задаются через атрибут
В свою очередь, память экономится из-за того, что у класса не создается
#std #slots
Python, аналогично другим динамическим языкам, таким как JavaScript, предоставляет возможность манипулирования объектами в рантайме, в том числе позволяет добавлять, изменять и удалять атрибуты. Цена этого – понижение скорости доступа к атрибутам и дополнительные расходы памяти.
Такое поведение нужно не всегда. Бывают случаи, когда мы точно знаем, какие атрибуты будут у наших экземпляров классов. Или же мы хотим ограничить добавление новых атрибутов. Именно для этого и существует
__slots__
.Слоты задаются через атрибут
__slots__
в классе:class SlotsClass:Теперь мы не можем добавлять новые атрибуты к нашим объектам. Скорость доступа к атрибутам повышается на 25-30%, потому что при доступе к ним их больше не надо вычислять.
slots = ('foo', 'bar')
>>> obj = SlotsClass()
>>> obj.foo = 5
>>> obj.foo
# 5
>>> obj.another_attribute = 'test'
Traceback (most recent call last):
File "python", line 5, in <module>
AttributeError: 'SlotsClass' object has no attribute 'another_attribute'
В свою очередь, память экономится из-за того, что у класса не создается
__dict__
, который как раз хранил атрибуты.#std #slots
Forwarded from Коробка с питоном
Коробка с питоном
Про __slots__ Python, аналогично другим динамическим языкам, таким как JavaScript, предоставляет возможность манипулирования объектами в рантайме, в том числе позволяет добавлять, изменять и удалять атрибуты. Цена этого – понижение скорости доступа к атрибутам…
__slots__ и наследование
Важно помнить, что при попытке унаследовать класс с
Из-за этого возникает неоднозначность, какой именно слот использовать в результирующем классе.
#std #slots
Важно помнить, что при попытке унаследовать класс с
__slots__
подкласс их унаследует, но так же и создаст __dict__
для новых атрибутов:class SlotsClass:Это стандартное и понятное поведение. Чтобы избежать создания
__slots__ = ('foo', 'bar')
class ChildSlotsClass(SlotsClass):
pass
>>> obj = ChildSlotsClass()
>>> obj.__slots__
# ('foo', 'bar')
>>> obj.foo = 5
>>> obj.test = 3
>>> obj.__dict__
# {'test': 3}
__dict__
, можно снова переопределить __slots__
в подклассе:class SlotsClass:А что с множественным наследованием?
__slots__ = ('foo', 'bar')
class ChildSlotsClass(SlotsClass):
__slots__ = ('baz',)
>>> obj = ChildSlotsClass()
>>> obj.foo = 5
>>> obj.baz = 6
>>> obj.something_new = 3
AttributeError: 'ChildSlotsClass' object has no attribute 'something_new'
class ClassA:Оно не работает. Потому-что каждый класс может иметь свои собственные
__slots__ = ('foo', 'bar',)
class ClassB:
__slots__ = ('baz',)
class C(ClassA, ClassB):
pass
TypeError: multiple bases have instance lay-out conflict
__slots__
, которые могут пересекаться с другими классами, а это может привести к тому, что объекты могут быть созданы неправильно или будут иметь непредсказуемое поведение. Из-за этого возникает неоднозначность, какой именно слот использовать в результирующем классе.
#std #slots