Находясь в обработчике исключений у вас есть 5 вариантов, что вы можете сделать:
Обработать исключение и подавить его
Обработать исключение и пробросить дальше - просто вызвать raise
Обработать исключение и выбросить новое исключение - вызвать raise Exception()
Обработать исключение и выбросить новое исключение и сохранить информацию об оригинальном - вызвать raise Exception() from e
Обработать исключение и выбросить новое исключение, но скрыть информацию об оригинальном исключении - вызвать raise Exception() from None
def func():
raise ConnectionError
# 1 вариант - обрабатывает и подавляет исключение
try:
func()
except ConnectionError as exc:
print('exception: ', type(exc), exc)
# получите сообщение:
# exception: <class 'ConnectionError'>
# 2 вариант - обрабатывает и пробрасывает оригинальное исключение дальше
try:
func()
except ConnectionError as exc:
print(exc)
raise
# получите следующее сообщение:
# exception: <class 'ConnectionError'>
# Traceback (most recent call last):
# File ".\z.py", line 6, in <module>
# func()
# File ".\z.py", line 2, in func
# raise ConnectionError
# ConnectionError
# 3 вариант - обработать и выбросить новое исключение из обработчика
# это будет воспринято, как произошло новое исключение, во время обработки оригинального
try:
func()
except ConnectionError as exc:
raise RuntimeError('Failed to open database')
# получите сообщение:
# Traceback (most recent call last):
# File ".\z.py", line 6, in <module>
# func()
# File ".\z.py", line 2, in func
# raise ConnectionError
# ConnectionError
# During handling of the above exception, another exception occurred:
# Traceback (most recent call last):
# File ".\z.py", line 8, in <module>
# raise RuntimeError('Failed to open database')# from None
# RuntimeError: Failed to open database
# 4 вариант - обработать и выбросить исключение (например, кастомное исключение вашей библиотеки)
# и сохранить информацию об оригинальном исключении
try:
func()
except ConnectionError as exc:
raise RuntimeError('Failed to open database') from exc
# получите следующее сообщение:
# Traceback (most recent call last):
# File ".\z.py", line 6, in <module>
# func()
# File ".\z.py", line 2, in func
# raise ConnectionError
# ConnectionError
# The above exception was the direct cause of the following exception:
# Traceback (most recent call last):
# File ".\z.py", line 8, in <module>
# raise RuntimeError('Failed to open database') from exc
# RuntimeError: Failed to open database
# Заметьте разницу в сообщении об оригинальном исключении:
# было During handling of the above exception, another exception occurred
# стало The above exception was the direct cause of the following exception
# разница я думаю понятна
# 5 вариант - обработать и выбросить исключение (например, кастомное исключение вашей библиотеки)
# и скрыть информацию об оригинальном сообщении:
try:
func()
except ConnectionError as exc:
raise RuntimeError('Failed to open database') from None
# получите следующее сообщение:
# Traceback (most recent call last):
# File ".\z.py", line 8, in <module>
# raise RuntimeError('Failed to open database') from None
# RuntimeError: Failed to open database
# как можете видеть - оригинальное исключение скрыто
Note: out-of-order designated initialization, nested designated initialization, mixing of designated initializers and regular initializers, and designated initialization of arrays are all supported in the C programming language, but are not allowed in C++.
У меня опыта с Qt будет меньше. Добавить щепотку многопоточности в прокси-дерево в ближайших планах.
По несуществующим индексам - я может быть вас не понял, но в моей практике я сталкиваюсь с невозможностью вносить изменения в исходную модель и приходится делать все в прокси-модели, в том числе и индексы для несуществующих элементов. Ну и там хочешь, не хочешь, но их обрабатывать надо правильно, т.к. если сходить в internalPointer чужого индекса, да если там еще и данных нет, то будет довольно больно.
По поводу кода - у меня были опасения, что за деревьями не будет видно леса. Т.к. объективно, чтобы продемонстрировать данную проблему, надо написать две модели и еще вью добавить, в которой, например, реализовать пользовательский интерфейс для группировки элементов.
В планах есть написать туториал, но это гораздо больше работы, чем небольшая заметка о конкретной проблеме.
С другой стороны с удовольствием послушал бы про ваш опыт.
Или, другой пример, вам необходимо реализовать группировку объектов на основе атрибутов или дать возможность пользователю произвольно группировать объекты исходного дерева. В этих случаях вам придется реализовать свою прокси-модель на основе QAbstractProxyModel.
Как ее правильно реализовать - об этом можно поговорить отдельно. Сегодня я хотел рассказать про ошибку, с которой вы можете столкнуться, если будете реализовывать прокси-модель из последнего примера:
Вот цитата из статьи, мне казалось, что в ней достаточно кратко описана бизнес-задача, которую мы пытаемся решить.
У вас, судя по комментариям, есть достаточный опыт, чтобы понять, что базовых возможностей для решения данной задачи не достаточно и необходимо делать свою реализацию прокси-модели. При условии, что у нас исходная модель, которую мы менять не можем (поэтому и заморачиваемся с прокси-моделью).
Если какие-то формулировки в статье не понятны - давайте их конструктивно обсуждать, чтобы сделать статью лучше.
Да, вы все правильно пишите, и базовая реализация QAbstractProxyModel именно так и делает. Это работает, пока нам требуется редактировать только те индексы, которые существуют в исходной модели.
Но проблема в том, что в моем случае (я об этом как раз написал в статье) у меня в прокси-модели существуют индексы, которые в исходной модели отсутствуют. Очевидно, что для таких индексов, что mapToSource, что mapFromSource вернут не валидный индекс. И, соответственно, редактирование работать не будет. Поэтому я проверяю, что если индекс принадлежит прокси-модели, то возвращаю этот индекс в качестве buddy.
Вы правы - я забыл перегрузить метод buddy (впрочем о этом я написал), вы правы что об этом написано в документации, но, к сожалению, не в самом очевидном месте - но тут тоже я написал, что надо внимательнее читать документацию.
А в статье я хотел показать насколько я был фрустрирован данной ситуацией.
Код там довольно прямолинейный (на питоне):
def buddy(self, index: QModelIndex) -> QModelIndex:
if index.isValid() and index.model() == self:
return index
return super().buddy(index)
Прежде чем написать свой комментарий, я конечно же ознакомился с этой вашей ссылкой (которая указана в тексте), но в ней нет ничего про реализацию вашего эвалюатора. То что вы используете префиксное дерево конечно похвально, но мне не, например, не очевидно зачем.
Простите меня, но кроме рекламы ваша статья ценности не несет. Сделать статью только с бенчмарками и с таким заголовком и не рассказать как вы это делаете - это неуважение к сообществу. Потому что подходы давно известны - есть ли у вас ноу-хау - не понятно.
Когда по основному вопросу вам оказалось нечего сказать, вы решили съехать на другую тему. У меня есть коллега, который очень часто любит вспоминать анекдот, про «а вот если бы у нее была шерсть», на мой взгляд это как раз про вас. Ну и в целом ваш комментарий попытка манипулировать, не надо так.
Если вы считаете, что между конкурентностью и параллелизмом нет никакой разницы - напишите статью. Сообщество с удовольствием обсудит.
На этом простите - продолжать обсуждение смысла не вижу.
Находясь в обработчике исключений у вас есть 5 вариантов, что вы можете сделать:
Обработать исключение и подавить его
Обработать исключение и пробросить дальше - просто вызвать raise
Обработать исключение и выбросить новое исключение - вызвать raise Exception()
Обработать исключение и выбросить новое исключение и сохранить информацию об оригинальном - вызвать raise Exception() from e
Обработать исключение и выбросить новое исключение, но скрыть информацию об оригинальном исключении - вызвать raise Exception() from None
PS. Простите за спам в почте - я победил редактор
Наверное у вас в компиляторе есть расширение для этого. Когда последний раз год назад я пробовал в VS2019 - не работало.
А они должны?
Aggregate initialization - cppreference.com
Note: out-of-order designated initialization, nested designated initialization, mixing of designated initializers and regular initializers, and designated initialization of arrays are all supported in the C programming language, but are not allowed in C++.
На хабре недавно был перевод статьи от создателя Github, о том, почему, на его взгляд, победил Github - Почему GitHub на самом деле победил: история глазами сооснователя / Хабр, там есть немного про BitBucket.
Понятно то оно понятно, но меня что-то перемкнуло и вроде и AVX рядом и вот это все - а понять не могу. Пришлось смотреть в оригинале.
Для таких как я - ОКМД - SIMD.
К сожалению, как я говорил выше, я не могу вносить изменения в исходную модель. Слишком много связанных трудозатрат получается.
А по поводу internalPointer - интересная информация, спасибо, надо будет изучить вопрос.
У меня опыта с Qt будет меньше. Добавить щепотку многопоточности в прокси-дерево в ближайших планах.
По несуществующим индексам - я может быть вас не понял, но в моей практике я сталкиваюсь с невозможностью вносить изменения в исходную модель и приходится делать все в прокси-модели, в том числе и индексы для несуществующих элементов. Ну и там хочешь, не хочешь, но их обрабатывать надо правильно, т.к. если сходить в internalPointer чужого индекса, да если там еще и данных нет, то будет довольно больно.
По поводу кода - у меня были опасения, что за деревьями не будет видно леса. Т.к. объективно, чтобы продемонстрировать данную проблему, надо написать две модели и еще вью добавить, в которой, например, реализовать пользовательский интерфейс для группировки элементов.
В планах есть написать туториал, но это гораздо больше работы, чем небольшая заметка о конкретной проблеме.
С другой стороны с удовольствием послушал бы про ваш опыт.
Вот цитата из статьи, мне казалось, что в ней достаточно кратко описана бизнес-задача, которую мы пытаемся решить.
У вас, судя по комментариям, есть достаточный опыт, чтобы понять, что базовых возможностей для решения данной задачи не достаточно и необходимо делать свою реализацию прокси-модели. При условии, что у нас исходная модель, которую мы менять не можем (поэтому и заморачиваемся с прокси-моделью).
Если какие-то формулировки в статье не понятны - давайте их конструктивно обсуждать, чтобы сделать статью лучше.
Да, вы все правильно пишите, и базовая реализация QAbstractProxyModel именно так и делает. Это работает, пока нам требуется редактировать только те индексы, которые существуют в исходной модели.
Но проблема в том, что в моем случае (я об этом как раз написал в статье) у меня в прокси-модели существуют индексы, которые в исходной модели отсутствуют. Очевидно, что для таких индексов, что mapToSource, что mapFromSource вернут не валидный индекс. И, соответственно, редактирование работать не будет. Поэтому я проверяю, что если индекс принадлежит прокси-модели, то возвращаю этот индекс в качестве buddy.
Вы правы - я забыл перегрузить метод buddy (впрочем о этом я написал), вы правы что об этом написано в документации, но, к сожалению, не в самом очевидном месте - но тут тоже я написал, что надо внимательнее читать документацию.
А в статье я хотел показать насколько я был фрустрирован данной ситуацией.
Код там довольно прямолинейный (на питоне):
У обоих римский алфавит...
Есть классическая уже книга - Типы в языках программирования - у нас делали перевод - Типы в языках программирования (tversu.ru)
На эту же тему было ранее - Кто быстрее создаёт списки в Python, list() или [] / Хабр (habr.com)
PS. man time.perf_counter
Можно использовать назначенную инициализацию, если допустимо передать один объект вместо кучи параметров - https://compiler-explorer.com/z/orM9sh9de
Сорри, только после отправки заметил что это дубль - https://habr.com/ru/articles/844988/#comment_27330472
Это называется Let it Crash. И, например, в Erlang-е довольно распространенная идиома.
Прежде чем написать свой комментарий, я конечно же ознакомился с этой вашей ссылкой (которая указана в тексте), но в ней нет ничего про реализацию вашего эвалюатора. То что вы используете префиксное дерево конечно похвально, но мне не, например, не очевидно зачем.
Простите меня, но кроме рекламы ваша статья ценности не несет. Сделать статью только с бенчмарками и с таким заголовком и не рассказать как вы это делаете - это неуважение к сообществу. Потому что подходы давно известны - есть ли у вас ноу-хау - не понятно.
Которые тоже вносят точку синхронизации.
Когда по основному вопросу вам оказалось нечего сказать, вы решили съехать на другую тему. У меня есть коллега, который очень часто любит вспоминать анекдот, про «а вот если бы у нее была шерсть», на мой взгляд это как раз про вас. Ну и в целом ваш комментарий попытка манипулировать, не надо так.
Если вы считаете, что между конкурентностью и параллелизмом нет никакой разницы - напишите статью. Сообщество с удовольствием обсудит.
На этом простите - продолжать обсуждение смысла не вижу.