Как поставить прочерк в Excel
Содержание
- Прочерк в Экселе
- Способ 1: форматирование диапазона
- Способ 2: нажатие кнопки Enter
- Способ 3: вставка символа
- Способ 4: добавление дополнительного символа
- Вопросы и ответы
Многие пользователи Excel при попытке поставить прочерк на листе испытывают немалые затруднения. Дело в том, что программа понимает тире, как знак «минус», и тут же преобразует значения в ячейке в формулу. Поэтому данный вопрос является довольно насущным. Давайте разберемся, как поставить прочерк в Excel.
Прочерк в Экселе
Часто при заполнении различных документов, отчетов, деклараций нужно указать, что ячейка, соответствующая какому-то конкретному показателю, не содержит значений. Для этих целей принято применять прочерк. Для программы Эксель данная возможность, существует, но воплотить её для неподготовленного пользователя довольно проблематично, так как прочерк тут же преобразуется в формулу. Чтобы избежать этого превращения, нужно выполнить определенные действия.
Способ 1: форматирование диапазона
Самый известный способ поставить прочерк в ячейке – это присвоить ей текстовый формат. Правда, этот вариант не всегда помогает.
- Выделяем ячейку, в которую нужно поставить прочерк. Кликаем по ней правой кнопкой мыши. В появившемся контекстном меню выбираем пункт «Формат ячейки». Можно вместо этих действий нажать на клавиатуре сочетание клавиш Ctrl+1.
- Запускается окно форматирования. Переходим во вкладку
После этого выделенной ячейке будет присвоено свойство текстового формата. Все введенные в нее значения будут восприниматься не как объекты для вычислений, а как простой текст. Теперь в данную область можно вводить символ «-» с клавиатуры и он отобразится именно как прочерк, а не будет восприниматься программой, как знак «минус».
Существует ещё один вариант переформатирования ячейки в текстовый вид. Для этого, находясь во вкладке «Главная», нужно кликнуть по выпадающему списку форматов данных, который расположен на ленте в блоке инструментов «Число». Открывается перечень доступных видов форматирования. В этом списке нужно просто выбрать пункт «Текстовый»
.Урок: Как изменить формат ячейки в Excel
Способ 2: нажатие кнопки Enter
Но данный способ не во всех случаях работает. Зачастую, даже после проведения этой процедуры при вводе символа «-» вместо нужного пользователю знака появляются все те же ссылки на другие диапазоны. Кроме того, это не всегда удобно, особенно если в таблице ячейки с прочерками чередуются с ячейками, заполненными данными. Во-первых, в этом случае вам придется форматировать каждую из них в отдельности, во-вторых, у ячеек данной таблицы будет разный формат, что тоже не всегда приемлемо. Но можно сделать и по-другому.
- Выделяем ячейку, в которую нужно поставить прочерк. Жмем на кнопку «Выровнять по центру», которая находится на ленте во вкладке «Главная» в группе инструментов «Выравнивание». А также кликаем по кнопке «Выровнять по середине
- Набираем в ячейке с клавиатуры символ «-». После этого не делаем никаких движений мышкой, а сразу жмем на кнопку Enter, чтобы перейти на следующую строку. Если вместо этого пользователь кликнет мышкой, то в ячейке, где должен стоять прочерк, опять появится формула.
Данный метод хорош своей простотой и тем, что работает при любом виде форматирования. Но, в то же время, используя его, нужно с осторожностью относиться к редактированию содержимого ячейки, так как из-за одного неправильного действия вместо прочерка может опять отобразиться формула.
Способ 3: вставка символа
Ещё один вариант написания прочерка в Эксель – это вставка символа.
- Выделяем ячейку, куда нужно вставить прочерк. Переходим во вкладку «Вставка». На ленте в блоке инструментов «Символы» кликаем по кнопке «Символ».
- Находясь во вкладке «Символы», устанавливаем в окне поля «Набор» параметр «Символы рамок». В центральной части окна ищем знак «─» и выделяем его. Затем жмем на кнопку «Вставить».
После этого прочерк отразится в выделенной ячейке.
Существует и другой вариант действий в рамках данного способа. Находясь в окне «Символ», переходим во вкладку «Специальные знаки». В открывшемся списке выделяем пункт «Длинное тире». Жмем на кнопку «Вставить». Результат будет тот же, что и в предыдущем варианте.
Данный способ хорош тем, что не нужно будет опасаться сделанного неправильного движения мышкой. Символ все равно не изменится на формулу. Кроме того, визуально прочерк поставленный данным способом выглядит лучше, чем короткий символ, набранный с клавиатуры.
Способ 4: добавление дополнительного символа
Кроме того, существует ещё один способ поставить прочерк. Правда, визуально этот вариант не для всех пользователей будет приемлемым, так как предполагает наличие в ячейке, кроме собственно знака «-», ещё одного символа.
- Выделяем ячейку, в которой нужно установить прочерк, и ставим в ней с клавиатуры символ «‘». Он располагается на той же кнопке, что и буква «Э» в кириллической раскладке. Затем тут же без пробела устанавливаем символ «-».
- Жмем на кнопку Enter или выделяем курсором с помощью мыши любую другую ячейку. При использовании данного способа это не принципиально важно. Как видим, после этих действий на листе был установлен знак прочерка, а дополнительный символ «’» заметен лишь в строке формул при выделении ячейки.
Существует целый ряд способов установить в ячейку прочерк, выбор между которыми пользователь может сделать согласно целям использования конкретного документа. Большинство людей при первой неудачной попытке поставить нужный символ пытаются сменить формат ячеек. К сожалению, это далеко не всегда срабатывает. К счастью, существуют и другие варианты выполнения данной задачи: переход на другую строку с помощью кнопки Enter, использование символов через кнопку на ленте, применение дополнительного знака «’». Каждый из этих способов имеет свои достоинства и недостатки, которые были описаны выше. Универсального варианта, который бы максимально подходил для установки прочерка в Экселе во всех возможных ситуациях, не существует.
Как сделать абзац в Инстаграм
- GIRL POWER
ПУТЕШЕСТВИЯ- О ТЕКСТАХ
- ВДОХНОВЕНИЕ
- КНИГИ
июня 24, 2017
Привет! Это Лена Сахарова, писатель, журналист и путешественник. У меня свой курс по текстам. И клуб, с которым вести блог в кайф.
И о том, как начать и не бросить блог, я регулярно пишу в Инстаграм. Я пишу тексты каждый день уже 12 лет — пишу для себя, для СМИ и в блог.
Абзацы — это ступеньки, по которым вы ведете читателя к сути. Один абзац — одна мысль.
Без них читатель не уловит сути и вряд ли дочитает до конца.
СРАВНИТЕ САМИ
Абзацев нет
Абзацы есть
смотреть этот пост в Инстаграм
СЕКРЕТНЫЙ ПРОБЕЛ
Если вы ставите отступы в самом Инстаграм, текст слипнется. Чтобы делить текст на абзацы, нужен секретный пробел.
Скопируйте пробел для Инстаграм здесь:
⠀— Вот он, в начале этой строки, перед тире.
Выделяйте, копируйте и вставляйте в свою запись.
КАК ИСПОЛЬЗОВАТЬ ПРОБЕЛ?
1. Открой запись в Инстаграм.
2. Удали пробел в конце предыдущего абзаца.
3. Перейди на новую строку — в айфоне для этого нажми кнопку «Ввод».
4. Вставь секретный пробел.
5. Перейди на новую строку.
6. Сохрани запись.
7. Магия сработала?
ЕЩЕ ОДИН СПОСОБ ПОСТАВИТЬ ПРОБЕЛ
В Телеграме есть бот text4insta.
Закидываете текст роботу — получаете тексты с абзацами.
Подпишитесь на мой инстаграм
Еще больше полезных и мотивирующих материалов для тех, кто ведет блог
ПОДПИСАТЬСЯ
ПРИХОДИТЕ НА МОЙ КУРС ПО ТЕКСТАМ ДЛЯ БЛОГОВ
Пробелы — это хорошо. Но куда важнее сам текст. Я очень хочу, чтобы вы почаще писали искренние тексты о себе, о жизни, о событиях, которые волнуют вас.
Поэтому я создала свой писательский курс.
За 21 день вы освоите приемы письма, узнаете, где брать идеи для постов и как писать, не дожидаясь вдохновения.
Каждый текст — это ваша новая возможность рассказать о себе, найти единомышленников, партнеров и клиентов.
ПРИСОЕДИНЯЙТЕСЬ К БЛОГЕРСКОМУ КЛУБУ
Блогерский клуб «С Сахарком» — онлайн комьюнити для тех, кто уже ведет блог или только начинает. В атмосфере поддержки и бережно к себе мы вместе растём и развиваем блоги, чтобы ярче жить свою жизнь ➜
✔ Комьюнити своих и мастермайнды
✔ Эксперты рядом + живые вебинары
✔ Библиотека, которая поможет выйти с блогом на новый уровень
✔ Шпаргалки по блогингу
ЧИТАЙТЕ ТАКЖЕ
ИНТЕРВЬЮ С ДИЗАЙНЕРОМ АДАМОМ КУРТЦОМ
длинных обратных вызовов | Документация Dash для Python
Мы рекомендуем использовать фоновые обратные вызовы с @dash.
callback(…, background=True)
вместоlong_callback
.
Аргументbackground=True
был представлен в Dash 2.6.0
и устраняет несколько ограничений с помощьюlong_callback
,
, включая его несовместимость с динамически добавляемыми компонентами и с
обратными вызовами сопоставления шаблонов.
long_callback
по-прежнему безопасно использовать, но больше не рекомендуется для версий Dash выше 2.6.0.
Большинство веб-серверов по умолчанию имеют 30-секундный тайм-аут, что является проблемой для обратных вызовов, выполнение которых занимает больше времени. Хотя вы можете увеличить время ожидания на веб-сервере, вы рискуете позволить длительным обратным вызовам использовать все рабочие процессы вашего приложения, препятствуя выполнению других запросов. Длинные обратные вызовы предлагают масштабируемое решение для использования длительных обратных вызовов.
Длинные обратные вызовы можно добавить в ваши приложения с помощью декоратора @app. long_callback
. Обратные вызовы с этим декоратором используют серверную часть, настроенную вами для запуска логики обратного вызова. В настоящее время есть два варианта:
Серверная часть DiskCache, выполняющая логику обратного вызова в отдельном процессе и сохраняющая результаты на диск с помощью библиотеки
diskcache
. Это самый простой бэкэнд для локальной разработки, но не рекомендуется для рабочей среды .Серверная часть Celery, которая выполняет логику обратного вызова в рабочем процессе Celery и возвращает результаты в приложение Dash через брокера Celery, например RabbitMQ или Redis. Это рекомендуется для производства, поскольку, в отличие от Disk Cache, оно использует очередь заданий и не будет случайно потреблять все ресурсы вашего сервера. Для получения дополнительной информации о преимуществах очередей заданий см.0031 Почему очереди заданий? раздел ниже.
Dash Enterprise упрощает развертывание Celery и Redis для использования длинных обратных вызовов в производственной среде. Узнайте цены или посмотрите Dash в действии на нашей следующей демонстрационной сессии.
Начало работы
В приведенных ниже примерах используется диспетчер diskcache
, для которого требуются библиотеки diskcache
, multiprocess
и psutil
:
$ pipps multiprocess installutil diskcache
Основные шаги
Первым шагом для использования длинных обратных вызовов является настройка экземпляра диспетчера длинных обратных вызовов с использованием выбранного вами бэкенда.
Декоратору @app.long_callback
требуется этот длинный экземпляр диспетчера обратных вызовов. Вы можете предоставить экземпляр менеджера конструктору приложения dash.Dash в качестве аргумента ключевого слова long_callback_manager
или в качестве аргумента manager
самому декоратору @app.long_callback
.
Декоратор @app.long_callback
поддерживает те же аргументы, что и обычный декоратор @app. callback
, но также включает поддержку нескольких дополнительных необязательных аргументов, описанных ниже: прогресс и progress_default
.
В следующих пяти примерах мы более подробно обсудим, как реализовать длинные обратные вызовы.
Пример 1: простой пример
Вот простой пример использования декоратора @app.long_callback
для регистрации функции обратного вызова, которая обновляет элемент html.P
количеством нажатий кнопки. Обратный вызов использует time.sleep
для имитации длительной операции.
время импорта импортировать тире из тире импортировать html из dash.long_callback импорт DiskcacheLongCallbackManager из dash.dependencies импортировать ввод, вывод ## Кэш диска импорт дискового кэша кэш = diskcache.Кэш("./кэш") long_callback_manager = DiskcacheLongCallbackManager(кэш) приложение = тире.Тире(__имя__) app.layout = html.Div( [ html.Div([html.P(id="paragraph_id", children=["Кнопка не нажата"])]), html. Button(id="button_id", kids="Выполнить задание!"), ] ) @app.long_callback( вывод = вывод («идентификатор_параграфа», «дети»), inputs=Input("button_id", "n_clicks"), менеджер=long_callback_manager, ) Обратный вызов защиты (n_clicks): время сна (2.0) return [f"Нажато {n_clicks} раз"] если __name__ == "__main__": app.run_server(отладка=Истина)
Пример 2. Отключение кнопки во время выполнения обратного вызова
Обратите внимание, что в предыдущем примере нет визуальной индикации того, что выполняется длительный обратный вызов. Пользователь может нажать кнопку «Выполнить задание!» кнопку несколько раз, прежде чем исходное задание сможет завершиться. Мы можем устранить эти недостатки, отключив кнопку во время выполнения обратного вызова и повторно включив ее после завершения обратного вызова.
Это достигается с помощью , использующего аргумент
для @app.long_callback
. Этот аргумент принимает список кортежей из 3 элементов. Первым элементом каждого кортежа должен быть объект зависимости Output
, ссылающийся на свойство компонента в макете приложения. Второй элемент — это значение, которое должно быть установлено для свойства во время выполнения обратного вызова, а третий элемент — это значение, которое должно быть установлено для свойства после завершения обратного вызова.
В этом примере используется с запуском
для установки свойства disabled
кнопки на True
во время выполнения обратного вызова и False
после его завершения.
В этом примере диспетчер длинных обратных вызовов предоставляется конструктору приложения dash.Dash
вместо декоратора @app.long_callback
.
время импорта импортировать тире из тире импортировать html из dash.long_callback импорт DiskcacheLongCallbackManager из dash.dependencies импортировать ввод, вывод ## Кэш диска импорт дискового кэша кэш = diskcache.Кэш(". /кэш") long_callback_manager = DiskcacheLongCallbackManager(кэш) app = dash.Dash(__name__, long_callback_manager=long_callback_manager) app.layout = html.Div( [ html.Div([html.P(id="paragraph_id", children=["Кнопка не нажата"])]), html.Button(id="button_id", kids="Выполнить задание!"), ] ) @app.long_callback( вывод = вывод («идентификатор_параграфа», «дети»), inputs=Input("button_id", "n_clicks"), работает=[ (Вывод ("button_id", "отключено"), Истина, Ложь), ], ) Обратный вызов защиты (n_clicks): время сна (2.0) return [f"Нажато {n_clicks} раз"] если __name__ == "__main__": app.run_server(отладка=Истина)
Пример 3. Отменяемый обратный вызов
Этот пример основывается на предыдущем примере, добавляя поддержку отмены длительного обратного вызова с использованием аргумента cancel
в декораторе @app.long_callback
. Мы устанавливаем аргумент cancel
в список объектов зависимостей Input
, которые ссылаются на свойство компонента в макете приложения. Когда значение этого свойства изменяется во время выполнения обратного вызова, обратный вызов отменяется. Обратите внимание, что значение свойства не имеет значения — любое изменение значения отменяет текущее задание (если оно есть).
время импорта импортировать тире из тире импортировать html из dash.long_callback импорт DiskcacheLongCallbackManager из dash.dependencies импортировать ввод, вывод ## Кэш диска импорт дискового кэша кэш = diskcache.Кэш("./кэш") long_callback_manager = DiskcacheLongCallbackManager(кэш) app = dash.Dash(__name__, long_callback_manager=long_callback_manager) app.layout = html.Div( [ html.Div([html.P(id="paragraph_id", children=["Кнопка не нажата"])]), html.Button(id="button_id", kids="Выполнить задание!"), html.Button(id="cancel_button_id", children="Отменить запущенное задание!"), ] ) @app.long_callback( вывод = вывод («идентификатор_параграфа», «дети»), inputs=Input("button_id", "n_clicks"), работает=[ (Вывод ("button_id", "отключено"), Истина, Ложь), (Вывод("cancel_button_id", "отключено"), False, True), ], отмена=[Ввод("cancel_button_id", "n_clicks")], ) Обратный вызов защиты (n_clicks): время сна (2. 0) return [f"Нажато {n_clicks} раз"] если __name__ == "__main__": app.run_server(отладка=Истина)
Пример 4. Индикатор выполнения
В этом примере используется аргумент progress
для декоратора @app.long_callback
для обновления индикатора выполнения во время выполнения обратного вызова. Мы устанавливаем аргумент progress
в группу зависимостей Output
, которая ссылается на свойства компонентов в макете приложения.
Когда группировка зависимостей назначается аргументу progress
аргумента @app.long_callback
, украшенная функция вызывается с новым специальным аргументом в качестве первого аргумента функции. Этот специальный аргумент, названный set_progress
в приведенном ниже примере — это дескриптор функции, который вызывает декорированная функция, чтобы предоставить приложению обновления о его текущем ходе. Функция set_progress
принимает один аргумент, который соответствует группе свойств, указанной в группе зависимостей Output
, переданной аргументу progress
@app. long_callback
.
время импорта импортировать тире из тире импортировать html из dash.long_callback импорт DiskcacheLongCallbackManager из dash.dependencies импортировать ввод, вывод ## Кэш диска импорт дискового кэша кэш = diskcache.Кэш("./кэш") long_callback_manager = DiskcacheLongCallbackManager(кэш) app = dash.Dash(__name__, long_callback_manager=long_callback_manager) app.layout = html.Div( [ html.Div( [ html.P(id="paragraph_id", children=["Кнопка не нажата"]), html.Progress(id="progress_bar"), ] ), html.Button(id="button_id", kids="Выполнить задание!"), html.Button(id="cancel_button_id", children="Отменить запущенное задание!"), ] ) @app.long_callback( вывод = вывод («идентификатор_параграфа», «дети»), inputs=Input("button_id", "n_clicks"), работает=[ (Вывод ("button_id", "отключено"), Истина, Ложь), (Вывод("cancel_button_id", "отключено"), False, True), ( Вывод("paragraph_id", "стиль"), {"видимость": "скрытый"}, {"видимость": "видимый"}, ), ( Вывод("прогресс_бар", "стиль"), {"видимость": "видимый"}, {"видимость": "скрытый"}, ), ], отмена=[Ввод("cancel_button_id", "n_clicks")], progress=[Вывод("progress_bar", "значение"), Output("progress_bar", "max")], ) обратный вызов def (set_progress, n_clicks): всего = 10 для i в диапазоне (всего): время сна (0,5) set_progress((str(i + 1), str(всего))) return [f"Нажато {n_clicks} раз"] если __name__ == "__main__": app. run_server (отладка = Истина, порт = 8054)
Пример 5: гистограмма прогресса
Аргумент progress
для декоратора @app.long_callback
может использоваться для обновления произвольных свойств компонента. В этом примере создается и обновляется гистограмма Plotly для отображения текущего состояния расчета.
В этом примере также используется аргумент progress_default
для long_callback
, чтобы указать группу значений, которые должны быть назначены компонентам, указанным в progress
аргумент, когда обратный вызов не выполняется. Если progress_default
не указан, все свойства зависимостей, указанные в progress
, устанавливаются равными None
, когда обратный вызов не выполняется. В этом случае progress_default
устанавливается на цифру с полосой нулевой ширины.
время импорта импортировать тире из тире импортировать html, dcc из dash. long_callback импорт DiskcacheLongCallbackManager из dash.dependencies импортировать ввод, вывод импортировать plotly.graph_objects как есть ## Кэш диска импорт дискового кэша кэш = diskcache.Кэш("./кэш") long_callback_manager = DiskcacheLongCallbackManager(кэш) def make_progress_graph (прогресс, всего): прогресс_граф = ( go.Figure(data=[go.Bar(x=[прогресс])]) .update_xaxes (диапазон = [0, всего]) .update_yaxes( showticklabels = Ложь, ) .update_layout (высота = 100, маржа = dict (t = 20, b = 40)) ) вернуть progress_graph app = dash.Dash(__name__, long_callback_manager=long_callback_manager) app.layout = html.Div( [ html.Div( [ html.P(id="paragraph_id", children=["Кнопка не нажата"]), dcc.Graph(id="progress_bar_graph", figure=make_progress_graph(0, 10)), ] ), html.Button(id="button_id", kids="Выполнить задание!"), html.Button(id="cancel_button_id", children="Отменить запущенное задание!"), ] ) @app. long_callback( вывод = вывод («идентификатор_параграфа», «дети»), inputs=Input("button_id", "n_clicks"), работает=[ (Вывод ("button_id", "отключено"), Истина, Ложь), (Вывод("cancel_button_id", "отключено"), False, True), ( Вывод("paragraph_id", "стиль"), {"видимость": "скрытый"}, {"видимость": "видимый"}, ), ( Вывод("progress_bar_graph", "стиль"), {"видимость": "видимый"}, {"видимость": "скрытый"}, ), ], отмена=[Ввод("cancel_button_id", "n_clicks")], прогресс = вывод ("progress_bar_graph", "цифра"), progress_default = make_progress_graph (0, 10), интервал=1000, ) обратный вызов def (set_progress, n_clicks): всего = 10 для i в диапазоне (всего): время сна (0,5) set_progress (сделать_progress_graph (я, 10)) return [f"Нажато {n_clicks} раз"] если __name__ == "__main__": app.run_server(отладка=Истина)
Пример с Celery/Redis
Мы рекомендуем использовать серверную часть Celery/Redis для производственных сред.
С Celery и Redis пример 3 выглядит так:
время импорта импортировать тире из тире импортировать html из dash.long_callback импортировать CeleryLongCallbackManager из dash.dependencies импортировать ввод, вывод из сельдерея импортный Сельдерей celery_app = Сельдерей( __name__, broker="redis://localhost:6379/0", backend="redis://localhost:6379/1" ) long_callback_manager = CeleryLongCallbackManager (celery_app) app = dash.Dash(__name__, long_callback_manager=long_callback_manager) app.layout = html.Div( [ html.Div([html.P(id="paragraph_id", children=["Кнопка не нажата"])]), html.Button(id="button_id", kids="Выполнить задание!"), html.Button(id="cancel_button_id", children="Отменить запущенное задание!"), ] ) @app.long_callback( вывод = вывод («идентификатор_параграфа», «дети»), inputs=Input("button_id", "n_clicks"), работает=[ (Вывод ("button_id", "отключено"), Истина, Ложь), (Вывод("cancel_button_id", "отключено"), False, True), ], отмена=[Ввод("cancel_button_id", "n_clicks")], ) Обратный вызов защиты (n_clicks): время сна (2. 0) return [f"Нажато {n_clicks} раз"] если __name__ == "__main__": app.run_server(отладка=Истина)
Вместо Diskcachelongcallbackmanager
, мы используем CeleryLongCallbackmanager
и импортный сельдерей, используя линию:
из Celerery Import Celery
Мы настраиваем приложение для селерии . Это хранится в переменной
long_callback_manager
и затем передается в приложение:
app = dash.Dash(__name__, long_callback_manager=long_callback_manager)
Результаты кэширования
Декоратор @app.long_callback
может дополнительно запоминать результаты функции обратного вызова посредством кэширования и предоставляет гибкий API для настройки повторного использования кэшированных результатов.
Кэширование с длинными обратными вызовами может помочь улучшить время отклика вашего приложения, но если вы хотите, чтобы пользователи могли сохранять и получать доступ к представлениям приложения в определенный момент времени, а также создавать отчеты в формате PDF из этих представлений, используйте Dash Enterprise Snapshot Engine. Поскольку Dash Enterprise Snapshot Engine хранит полную запись результатов, вы можете отслеживать, как результат для определенного набора параметров меняется с течением времени.
Для длительных обратных вызовов, когда вам не нужен доступ к прошлым результатам, используйте длинные обратные вызовы.
Как это работает
Вот подробное описание того, как работает кэширование в long_callback
. Концептуально вы можете представить, что словарь связан с каждой оформленной функцией обратного вызова. Каждый раз, когда вызывается украшенная функция, входные аргументы функции (и, возможно, другая информация об окружении) хэшируются для генерации ключа. 9Затем декоратор 0005 long_callback проверяет словарь, чтобы увидеть, не сохранено ли уже значение с использованием этого ключа. Если да, декорированная функция не вызывается, а возвращается кэшированный результат. Если нет, то вызывается функция, и результат сохраняется в словаре с использованием соответствующего ключа.
Встроенный декоратор functools.lru_cache
использует Python dict
точно так же. С Dash ситуация немного сложнее по двум причинам:
- Мы можем захотеть, чтобы кеш сохранялся при перезапуске сервера.
- Когда приложение обслуживается с использованием нескольких процессов (например, несколько рабочих процессов
gunicorn
на одном сервере или несколько серверов за балансировщиком нагрузки), мы можем захотеть использовать кешированные значения для всех этих процессов.
По этим причинам простой Python dict
не является подходящим хранилищем для кэширования обратных вызовов Dash. Вместо этого long_callback
использует текущий диспетчер обратного вызова DiskCache или Celery для хранения кэшированных результатов.
Требования к гибкости кэширования
Для поддержки кэширования в различных сценариях использования при разработке и производстве, long_callback
может быть настроен с помощью одной или нескольких функций без аргументов, где возвращаемые значения этих функций объединяются с входными аргументами функции, когда генерация ключа кэша. Несколько распространенных вариантов использования описаны ниже.
Включение кэширования
Кэширование включается путем предоставления одной или нескольких функций с нулевым аргументом для cache_by
аргумент long_callback
. Эти функции вызываются каждый раз, когда проверяется состояние функции long_callback
, а их возвращаемые значения хэшируются как часть ключа кэша.
Вот пример использования диспетчера обратного вызова DiskCache. В этом примере для аргумента cache_by
задана функция lambda
, которая возвращает фиксированный UUID, который генерируется случайным образом во время инициализации приложения. Значение этого cache_by
заключается в том, что кеш используется совместно для всех вызовов обратного вызова во всех пользовательских сеансах, которые обрабатываются одним экземпляром сервера. При каждом перезапуске серверного процесса кэш очищается и создается новый UUID.
время импорта из uuid импортировать uuid4 импортировать тире из тире импортировать html из dash. long_callback импорт DiskcacheLongCallbackManager из dash.dependencies импортировать ввод, вывод ## Кэш диска импорт дискового кэша launch_uid = uuid4 () кэш = diskcache.Кэш("./кэш") long_callback_manager = DiskcacheLongCallbackManager( кеш, cache_by=[лямбда: launch_uid], expire=60, ) app = dash.Dash(__name__, long_callback_manager=long_callback_manager) app.layout = html.Div( [ html.Div([html.P(id="paragraph_id", children=["Кнопка не нажата"])]), html.Button(id="button_id", kids="Выполнить задание!"), html.Button(id="cancel_button_id", children="Отменить запущенное задание!"), ] ) @app.long_callback( вывод = (выход ("paragraph_id", "дети"), вывод ("button_id", "n_clicks")), inputs=Input("button_id", "n_clicks"), работает=[ (Вывод ("button_id", "отключено"), Истина, Ложь), (Вывод("cancel_button_id", "отключено"), False, True), ], отмена=[Ввод("cancel_button_id", "n_clicks")], ) Обратный вызов защиты (n_clicks): время сна (2. 0) return [f"Нажато {n_clicks} раз"], (n_clicks или 0) % 4 если __name__ == "__main__": app.run_server(отладка=Истина)
Здесь вы можете видеть, что для запуска функции обратного вызова требуется несколько секунд, но кешированные результаты используются после n_clicks
циклов возврата к 0. Взаимодействуя с приложением на отдельной вкладке, вы можете увидеть, что кэшированные результаты распределяются между сеансами пользователей.
Исключение свойств из расчета ключа кэша
Декоратор @app.long_callback
имеет аргумент cache_args_to_skip
, который можно использовать для исключения свойств, указанных вами при вычислении ключа кэша. Например, вы, вероятно, не захотите включать кнопку n_clicks
в ключе кеша, потому что каждый раз при нажатии на него будет новое значение, и в этом случае вы можете использовать cache_args_to_skip
.
Если обратный вызов настроен с аргументами ключевого слова ( Input/State
указан в словаре), cache_args_to_skip
должен быть списком имен аргументов в виде строк. В противном случае это должен быть список индексов аргументов в виде целых чисел. Дополнительную информацию об аргументах ключевых слов см. в главе «Гибкие сигнатуры обратного вызова».
Рабочие процессы функций Cache_by
Вы можете использовать функции cache_by
для реализации различных политик кэширования. Вот несколько примеров:
- Функция
cache_by
может возвращать время модификации файла набора данных, чтобы автоматически сделать кэш недействительным при изменении входного набора данных. - В настройках развертывания Heroku или Dash Enterprise функция
cache_by
может возвращать git-хэш приложения, что позволяет сохранять кеш при повторных развертываниях, но делает его недействительным при изменении источника приложения. - В настройках Dash Enterprise функция
cache_by
может возвращать пользовательские метаданные, чтобы предотвратить совместное использование кэшированных значений между аутентифицированными пользователями.
Установка срока действия для записей кэша
Как с CeleryLongCallbackManager
, так и с DiskcacheLongCallbackManager
можно использовать аргумент expire
, чтобы ограничить время хранения записи кэша в базе данных. Это количество секунд, в течение которых запись кэша должна храниться после ее последнего использования. При доступе к записи таймер перезапускается.
celery_app = Сельдерей( __name__, broker="redis://localhost:6379/0", backend="redis://localhost:6379/1" ) long_callback_manager = CeleryLongCallbackManager (celery_app, срок действия = 100)
Ограничения
- Длинные обратные вызовы поддерживают дисковый кэш/многопроцессорность в качестве серверной части, что идеально подходит для сред разработки и может быть проще в настройке при работе в Windows. Однако для производственных сред мы рекомендуем Celery/Redis.
- Вы не можете получить доступ к предыдущим результатам, возвращенным длинным обратным вызовом. Эта функция доступна в Snapshot Engine Dash Enterprise.
- Зависимости сопоставления шаблонов не поддерживаются с длинными обратными вызовами. Ошибка возникает, если идентификатор обратного вызова содержит
ALL
,MATCH
илиALL_SMALLER
. -
dash.callback_context
не поддерживается. - Если зависимости
Input/State/Output
не существуют при запуске приложения (если они ссылаются на компоненты, сгенерированные другим обратным вызовом),submit_callback_exceptions=True
не препятствует тому, чтобы Dash вызывал ошибки проверки обратного вызова. Мы рекомендуем следующий подход:
- Приложение должно предоставить validation_layout, который содержит все компоненты, на которые ссылаются обратные вызовы в приложении.
- Аргумент
prevent_initial_call
дляapp.long_callback
должен иметь значениеTrue
.
Почему очереди заданий?
Когда ваше приложение развертывается в рабочей среде, конечное число ЦП обслуживает запросы для этого приложения.
Обратные вызовы, которые занимают более 30 секунд, часто имеют тайм-ауты при развертывании в рабочей среде. И даже обратные вызовы, которые занимают менее 30 секунд, могут связать все доступные ресурсы сервера, когда несколько пользователей одновременно обращаются к вашему приложению. Когда все ЦП обрабатывают обратные вызовы, новые посетители вашего приложения видят пустой экран и, в конечном итоге, сообщение «Сервер истек».
Очереди заданий являются решением этих проблем с тайм-аутом. Как и веб-процессы, обслуживающие ваше приложение Dash, очереди заданий работают с выделенным количеством процессорных ресурсов. Эти работники выполняют задания по одному и не имеют тайм-аутов. Пока работники очереди заданий обрабатывают данные, веб-процессы, обслуживающие приложение Dash, и обычные обратные вызовы отображают информативные экраны загрузки, индикаторы выполнения и результаты очередей заданий. Конечные пользователи никогда не видят время ожидания и всегда видят отзывчивое приложение.
Дополнительные ресурсы
Знакомство с сельдереем
Документация Redis
Руководство по DiskCache
Длинные обратные вызовы были разработаны Dash Labs. Мы получили много отзывов от пользователей на протяжении всей разработки. Вы можете увидеть исходные обсуждения этой функции сообществом здесь:
- dash-labs-0-3-0-app-long-callback-support
- dash-labs-0-4-0-long-callback-caching-and-windows-support
Справочник
Справочник по API для длинных обратных вызовов
Пунктуационные особенности: длинное тире
Опубликовано Пэм Нельсон и подано в Руководстве по грамматике старого треугольника.
Редакторы копирайтеров могут быть придирчивыми. Нам нравится точность, ясность и последовательность. Нам нравится иметь вескую причину для выхода за рамки. Недавнее сообщение коллеги, в котором тире было названо «банальной пунктуационной гиперболой», другим коллегам показалось резким и жестким. На самом деле, когда меня впервые наняли в N&O в 1987 нам сказали использовать дефисы экономно. Кажется, что-то изменилось за последние 10 лет или около того. Теперь нашу копию можно украсить штрихами.
Я решил немного изучить использование тире, также известного как длинное тире («длинное тире» — это печатный термин, обозначающий ширину) или длинное тире. Я хотел узнать правила использования тире.
(В этом посте я не рассматриваю короткое тире, которое редко используется в нашей газете. Я буду использовать два дефиса рядом для обозначения длинного тире в этом посте.)
Во-первых, Strunk & White, как заметил один из коллег, говорит о приборной панели следующее:
«Используйте тире, чтобы обозначить внезапный перерыв или прерывание, а также для объявления длинного аппозитива резюме. Дефис — это знак разделения сильнее, чем двоеточие, и более мягкий, чем круглые скобки. Используйте тире только тогда, когда это более распространенный знак пунктуации кажется неадекватной».
Сайт «Путеводитель по грамматике и письму» Столичного муниципального колледжа открывает страницу на тире с замечательной цитатой писателя-ученого Льюиса Томаса:
«Черточка — удобный прибор, неформальный и по существу шутливый, говорящий о том, что вы собираетесь взлететь другим курсом, но все же как-то связанный с текущим курсом, — только надо помнить, что черточка есть, и либо поставьте второй тире в конце понятия, чтобы дать читателю понять, что он вернулся на курс, либо в конце предложения, как здесь, точкой «.
В «Руководстве по грамматике и письму» тире называется «супер-запятая» и предлагается учащимся отказаться от тире вместо запятой. Совет хороший, но субъективный. Может быть, я думаю, что запятые подойдут, но другой автор считает, что без тире разрыв недостаточно силен.
Тире делают больший акцент на выделенных словах. В «Руководстве по пунктуации и стилю» Merriam-Webster, второе издание, говорится, что тире «обозначает резкое изменение или разрыв в структуре предложения». Пример: Почти все мы хотели посетить музей — Сьюзен хотела пройтись по магазинам. Я предпочитаю точку с запятой в этом месте, но кто-то другой может возразить, что в предложении нужно напряжение длинного тире — возможно, для обозначения раздражения.
В наши дни тире часто используются для связи двух предложений. я старомоден; Я думаю, что точки с запятой (или запятая и координирующий союз) лучше всего подходят для связи двух независимых предложений.
Иногда набор длинных дефисов действует как запятые и круглые скобки: для вставки пояснительных или уточняющих фраз. Пример: Когда я был ребенком, мы ходили в горы — в основном на Блоуинг-Рок или Бун — на выходные. В этом случае подойдут запятые, но автор может использовать тире для выделения. Другой пример: Мы ездили в горы — я был вынужденным пассажиром на заднем сиденье — почти каждые выходные летом. Здесь подойдут скобки. Некоторым авторам скобки могут показаться слишком резкими; они хотят, чтобы поток продолжался, даже подчеркивая в сторону.