что значит распаковка ячеек
Простая и расширенная распаковка списков и кортежей.
Целевой ссылкой в операции присваивания может служить список, состоящий из двух и более ссылок, разделенных запятыми, которые могут заключаться в необязательные круглые или квадратные скобки.
Присваивание с распаковкой можно использовать для обмена значениями переменных:
В обеих инструкциях присваивания требуется, чтобы объект iterable имел по крайней мере два элемента. Эту форму операции присваивания называют расширенной распаковкой.
Глубокая или расширенная распаковка, в некотором смысле похожа на множественное присваивание. Множественное присваивание позволяет сопоставить длину итерации в правой части присваивания и получить каждый элемент в переменной. Подобным образом глубокая распаковка позволяет сопоставить форму того, что находится в правой части задания.
Например, используя множественное присваивание дважды, можно сделать следующее:
Но если необходимо получить отдельные значения RGB, то можно сразу использовать глубокую распаковку:
Однако, если написать функцию, которая использует глубокую/расширенную распаковку, то можно поймать ошибку:
Примеры распаковки/упаковки последовательностей.
Пример реализации функции, похожей на функцию reduce из модуля functools при помощи распаковки последовательности.
Распаковка итерируемых объектов в переменные с помощью расширенной распаковки:
Распаковка итерируемых объектов может быть вложенной:
Теперь представим, что есть список с несколькими цветами и нужно вычислить оттенки серого. Для этого можно использовать глубокую распаковку в цикле for/in (а также используя генератор списка):
Упаковка-преобразование и распаковка-преобразование (Руководство по программированию на C#)
Упаковка представляет собой процесс преобразования типа значения в тип object или в любой другой тип интерфейса, реализуемый этим типом значения. Когда тип значения упаковывается общеязыковой средой выполнения (CLR), он инкапсулирует значение внутри экземпляра System.Object и сохраняет его в управляемой куче. Операция распаковки извлекает тип значения из объекта. Упаковка является неявной; распаковка является явной. Понятия упаковки и распаковки лежат в основе единой системы типов C#, в которой значение любого типа можно рассматривать как объект.
Затем можно выполнить операцию распаковки объекта o и присвоить его целочисленной переменной i :
Следующий пример иллюстрирует использование упаковки в C#.
Производительность
По сравнению с простыми операциями присваивания операции упаковки и распаковки являются весьма затратными процессами с точки зрения вычислений. При выполнении упаковки типа значения необходимо создать и разместить новый объект. Объем вычислений при выполнении операции распаковки, хотя и в меньшей степени, но тоже весьма значителен. Дополнительные сведения см. в разделе Производительность.
Упаковка
Упаковка используется для хранения типов значений в куче со сбором мусора. Упаковка представляет собой неявное преобразование типа значения в тип object или в любой другой тип интерфейса, реализуемый этим типом значения. При упаковке типа значения в куче выделяется экземпляр объекта и выполняется копирование значения в этот новый объект.
Рассмотрим следующее объявление переменной типа значения.
Можно также выполнять упаковку явным образом, как в следующем примере, однако явная упаковка не является обязательной.
Пример
Распаковка
Распаковка является явным преобразованием из типа object в тип значения или из типа интерфейса в тип значения, реализующего этот интерфейс. Операция распаковки состоит из следующих действий:
проверка экземпляра объекта на то, что он является упакованным значением заданного типа значения;
копирование значения из экземпляра в переменную типа значения.
В следующем коде показаны операции по упаковке и распаковке.
На рисунке ниже представлен результат выполнения этого кода.
Для успешной распаковки типов значений во время выполнения необходимо, чтобы экземпляр, который распаковывается, был ссылкой на объект, предварительно созданный с помощью упаковки экземпляра этого типа значения. Попытка распаковать null создает исключение NullReferenceException. Попытка распаковать ссылку на несовместимый тип значения создает исключение InvalidCastException.
Пример
При выполнении этой программы выводится следующий результат:
Specified cast is not valid. Error: Incorrect unboxing.
При изменении оператора:
будет выполнено преобразование со следующим результатом:
Спецификация языка C#
Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.
На мгновение быстрее: измеряем время упаковки и распаковки значимых типов данных
Доброго дня, Хабр!
Многие неопытные разработчики не всегда знают и понимают, что же происходит за кулисами их кода. Сейчас речь пойдет об упаковке и распаковке значимых типов данных (по-русски это звучит ужасно, поэтому «boxing and unboxing value types»).
Под катом небольшой пример и измерение времени выполнения.
Что такое упаковка (boxing)?
Коротко. Есть значимые типы данных (value types) и ссылочные (reference types). Переменные значимых типов данных хранят само значение (спасибо, кэп!), переменные ссылочных типов данных — ссылку на участок в памяти, где хранится это значение.
Это значимый тип данных. Значение переменной valType будет храниться в стэке. Многие стандартные типы данных — значимые (int, byte, long, bool и т.д.).
Дальше если мы попробуем сделать вот так:
И получим в результате переменную ссылочного типа (refType). Тут произойдет следующее: сначала в стэке появится значение переменной valType (значимый тип), потом в памяти будет создан контейнер для хранения значения этой переменной (в нашем случае контейнер для переменной типа int, то есть 4 байта под значение + sync block index (еще 4 байта)), а вот уже указатель на этот контейнер и будет храниться в нашей переменной ссылочного типа (refType). Этот процесс называется упаковка (boxing).
Подробности можно посмотреть тут, а лучше прочитать в книжке Дж.Рихтера «CLR via C#» (Глава 5).
Самое неприятное в этих операциях то, что они происходят неявно.
Например, мы хотим вывести число в консоль. Так:
В чем разница? Давайте посмотрим на результат компиляции в MSIL (сделать это можно утилитой ILdasm.exe):
Во втором случае мы видим команду box, которая и выполняет упаковку.
Чтобы понять откуда она взялась, взглянем на сигнатуру метода Console.WriteLine и заметим, что их есть аж 18 штук.
В первом вызове используется такая сигнатура:
Тут все просто — этот метод принимает значимый тип данных int, передаем мы значение типа int, происходит передача параметра по значению. Упаковка тут не нужна.
Во втором случае используется другая сигнатура:
С передачей форматной строки понятно: требуется строка — мы передаем строку. А с аргументом arg0 чуть сложнее: метод просит от нас объект ссылочного типа данных object, а передаем мы в метод значение типа int. Вот тут и нужна упаковка. В результате чего в памяти создается контейнер для типа int, в него копируется значение 20, и указатель на этот контейнер попадает в аргумент arg0.
Теперь попробуем посчитать, сильно ли замедляют данные операции наш код.
Для этого я написал небольшой кусочек кода:
Результат выполнения я получил следующий (процессор Intel Core i5 750 2.67GHz, 4 ядра, выполнялось на одном):
Итого в среднем почти 64мс на 10млн. операций упаковки.
Вывод
В качестве вывода хочу сказать, что все вышеизложенное вовсе не повод параноидально выискивать дизассемблером boxing’и в своем коде и добиваться лишнего миллиметра в секунду на скорости сто километров в час. Нет, конечно, это полный бред. Но понимать, что на самом деле происходит в вашем коде, важно. И в какой-то момент лишняя операция в цикле, выполняемом миллиарды раз, может стать критичной.
UPD! В комментариях пользователь exmachine подсказывает, что я не совсем корректно проводил измерения. Вот результаты с учетом поправок:
UPD2! Пользователь mstyura напомнил, что ранее на Хабре подобный вопрос уже освещался. Советую заглянуть и туда для дополнительной информации.
TikTok: объясняем, что такое «рек», «чек», «краш» и другие термины
TikTok — это целая вселенная со своими звездами, трендами, самыми популярными треками и флешмобами. Есть и свой сленг: «бумер», «рек», POV и другие термины, без которых разобраться будет сложно! Чтобы ты не запутался, собрали словарь самых важных понятий из TikTok.
Бумер — человек старшего поколения (больше 30 лет). Фразу «Окей, бумер» чаще всего используют для выражения пренебрежительного отношения к старомодным взглядам бумеров.
POV — расшифровывается как Point of View («Точка зрения) и означает повествование от первого лица, то есть съемку «глазами» какого-либо одушевленного или неодушевленного предмета. Например, «POV: Что видит мое зеркало, когда я собираюсь» или «POV: Ты встретил меня на вечеринке и вспомнил наши отношения».
##pov Ты делала интимные фотки для парня и твой брат тебя застукал 😅
Рек — сокращение от «Рекомендации». Пользователи добавляют этот хэштег, чтобы попасть в специальную подборку TikTok на главной странице приложения.
Чек — от английского Check — Проверить. В таких видео пользователи что-нибудь проверяют и показывают на камеру: есть «чеки» косметичек, гардероба и даже, например, парней из класса.
Краш — от английского Crush — Сокрушать или сокрушаться. В TikTok «крашем» называют человека, в которого ты влюблен или который тебе очень нравится.
Дуэт — так называют реакции на ролики других пользователей. В ленте это выглядит как коллаж из двух видео: твоего и оригинального.
Туториал — это обучающие видео: в них пользователи показывают, как повторить тот или иной эффект, какие приложения использовать и как станцевать танец из «трендов».
Простой экспорт в Excel XLSX
В продолжение темы, начатой в предыдущей статье, хочу поделиться своим опытом экспорта данных, в частности, в формате XLSX.
Итак, кому интересно, как заполнить XLSX без больших и сложных библиотек, прошу под кат.
Недавно передо мной возникла задача экспортировать непредсказуемый по размеру объем табличных данных в формате XLSX. Как любой здравомыслящий программист, первым делом полез искать готовые решения.
Почти сразу наткнулся на библиотеку PHPExcel. Мощное решение, с кучей разных функций и возможностей. Порывшись еще немного нашел отзывы программистов о ней. В частности, на форумах встречаются жалобы на скорость работы и отказ работать с большим объемом данных. Отметил библиотеку как один из вариантов решения и начал искать дальше.
Находил еще несколько библиотек для работы с XLSX, но все они были или забытыми, т.к. не обновлялись по 2-3 года, или обязательно тянули за собой сторонние библиотеки, или использовали DOM для работы с файлами, что мне не очень нравилось. Каждый раз, натыкаясь на очередную библиотеку и изучая механизмы ее работы, ловил себя на мысли, что все это «из пушки по воробьям». Не нужно мне такое сложное решение!
Признаюсь честно, изучив поверхностно каждое из найденных решений, не стал ставить и тестировать ни одного. Мне нужно было более простое и надежное, как танк, решение.
Задача
Реализация
Изначально очень хотел создавать все файлы, из которых состоит XLSX, кодом, но, к счастью, быстро понял бессмысленность своей идеи. И родилось иное, более правильно и простое решение. Надо с помощью Microsoft Excel создать файл XLSX в таком виде, в каком он нужен в итоге, но без данных, иными словами — шаблон, а потом, с помощью кода, только добавить данные!
В таком случае, класс должен будет распаковывать шаблон в отдельный каталог, вносить изменения в /xl/worksheets/sheet1.xml и упаковывать содержимое каталога обратно в XLSX.
В объявлении класса присутствуют публичные переменные:
$templateFile – имя файла шаблона
$exportDir – папка, в которую будет распакован шаблон, разумеется с необходимыми правами доступа.
Конструктор класса принимает имя будущего файла, количество колонок и рядов. Потом проверяет, что имя файла корректно, папка для распаковки шаблона существует и формирует полное имя конечной папки для распаковки шаблона.
После создания класса можно распаковать шаблон и открыть на запись sheet1.xml. На самом деле я не просто дописываю в файл, а полностью его перезаписываю. Однажды взяв из него начальную строку, вношу в нее изменение в тэге dimension, который отражает размер экспортируемого диапазона, и записываю в файл.
Обеспечить скорость работы и возможность работы с большим объемом данных позволяют функции resetRow и flushRow. Они отвечают за очистку текущего ряда в памяти и запись текущего ряда на диск.
А вот сохранение значений ячеек с разными типами оказалось не такой простой задачей.
Запись строки
Казалось бы, что сложного записать строковое значение в файл. Однако, в XLSX все не так просто. Все строки внутри XLSX хранятся в отдельном файле /xl/sharedStrings.xml. В ячейки записываются не строковые значения, а их порядковые номера — индексы. Разумное решение с точки зрения сокращения размера файла.
Но такое решение неудобно с точки зрения программного заполнения шаблона. Если выполнять указанное требование, то мне бы пришлось выполнять отдельный проход по всем строковым значениям в массиве данных, исключать повторяющиеся, сохранять их в sharedStrings.xml, проиндексировать и вместо значений в исходном массиве вписать их индексы. Медленно и неудобно.
Оказывается, можно обойти требование и сохранять строковые значения ячеек прямо в ячейках. Но в этом случае формат записи будет иной:
Запись числа
Никаких сложностей с записью целых или дробных чисел не возникло. Все просто:
Запись даты и времени
Дата и время хранятся в виде количества секунд прошедших с 01.01.1970 поделенных на количество секунд в сутках. Причем, в вычислении допущена ошибка с определением високосного года. В общем, не вдаваясь в подробности, которые несложно найти в сети, чтобы корректно вычислять дату пришлось объявить в классе две константы:
ZERO_TIMESTAMP – смещение даты в формате Excel от UNIX_TIMESTAMP
SEC_IN_DAY – секунд в сутках.
После вычисления значения даты и времени, целая часть дроби – это дата, дробная часть – время:
После записи всех данных остается закрыть рабочий лист и рабочую книгу.
Применение
Как и раньше, использование описанного класса основано на экспорте данных с помощью провайдера CArrayDataProvider. Предполагая, что объем экспортируемых данных может оказаться очень большим, применен специальный итератор CDataProviderIterator, который перебирает возвращаемые данные по 100 записей (можно указать иное число записей).
Кому интересно, может получить исходный код моего класса AlxdExportXLSX совершенно безвозмездно.