Новые кодеры иногда пишут такой код:
my_calculator.button_0 = tkinter.Button(root, text=0)
my_calculator.button_1 = tkinter.Button(root, text=1)
my_calculator.button_2 = tkinter.Button(root, text=2)
...
Затем кодер остается с кучей именованных переменных с усилием кодирования O ( m * n ), где m - это число именованных переменных, а n - это количество раз, к которому необходимо получить доступ к группе переменных (включая создание) , Более проницательный новичок отмечает, что единственная разница в каждой из этих строк - это число, которое изменяется на основе правила и решает использовать цикл. Тем не менее, они зациклились на том, как динамически создавать эти имена переменных, и могут попробовать что-то вроде этого:
for i in range(10):
my_calculator.('button_%d' % i) = tkinter.Button(root, text=i)
Вскоре они обнаруживают, что это не сработает.
Если программа требует произвольных переменных «имена», лучше всего подходит словарь, как объясняется в других ответах. Однако, если вы просто пытаетесь создать много переменных, и вы не возражаете ссылаться на них с последовательностью целых чисел, вы, вероятно, ищете list
. Это особенно верно, если ваши данные однородны, например, ежедневные показания температуры, еженедельные оценки викторины или сетка графических виджета.
Это можно собрать следующим образом:
my_calculator.buttons = []
for i in range(10):
my_calculator.buttons.append(tkinter.Button(root, text=i))
Этот list
также может быть создан в одной строке с пониманием:
my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]
Результат в любом случае - это заполненный list
, с первым элементом, к которому обращаются с помощью my_calculator.buttons[0]
, следующего с my_calculator.buttons[1]
и т. д. Имя переменной «base» становится именем list
, и для доступа к нему используется различный идентификатор.
Наконец, не забудьте другие структуры данных, такие как set
- это аналогично словарю, за исключением того, что каждое «имя» не имеет привязанного к нему значения. Если вам просто нужна «сумка» объектов, это может быть отличным выбором. Вместо этого:
keyword_1 = 'apple'
keyword_2 = 'banana'
if query == keyword_1 or query == keyword_2:
print('Match.')
У вас будет следующее:
keywords = {'apple', 'banana'}
if query in keywords:
print('Match.')
Используйте последовательность list
для последовательности похожих объектов, a set
для произвольного - помещенный пакет предметов или dict
для мешка с именами со связанными значениями.
неа. C ++ не генерирует исключения, когда вы делаете что-то плохое, что может привести к поражению производительности. Такие вещи, как нарушения доступа или деление на нулевые ошибки, скорее напоминают «машинные» исключения, а не вещи на уровне языка, которые вы можете поймать.
Как уже говорилось, для платформы Windows не существует способа поставщика Microsoft / компилятора. Однако, очевидно, полезно поймать эти типы исключений в обычном try {} catch (исключение ex) {} для сообщения об ошибках и более изящном выходе вашего приложения (как говорит JaredPar, теперь приложение, вероятно, находится в беде) , Мы используем _se_translator_function в простой оболочке класса, которая позволяет нам улавливать следующие исключения в aa try-обработчике:
DECLARE_EXCEPTION_CLASS(datatype_misalignment)
DECLARE_EXCEPTION_CLASS(breakpoint)
DECLARE_EXCEPTION_CLASS(single_step)
DECLARE_EXCEPTION_CLASS(array_bounds_exceeded)
DECLARE_EXCEPTION_CLASS(flt_denormal_operand)
DECLARE_EXCEPTION_CLASS(flt_divide_by_zero)
DECLARE_EXCEPTION_CLASS(flt_inexact_result)
DECLARE_EXCEPTION_CLASS(flt_invalid_operation)
DECLARE_EXCEPTION_CLASS(flt_overflow)
DECLARE_EXCEPTION_CLASS(flt_stack_check)
DECLARE_EXCEPTION_CLASS(flt_underflow)
DECLARE_EXCEPTION_CLASS(int_divide_by_zero)
DECLARE_EXCEPTION_CLASS(int_overflow)
DECLARE_EXCEPTION_CLASS(priv_instruction)
DECLARE_EXCEPTION_CLASS(in_page_error)
DECLARE_EXCEPTION_CLASS(illegal_instruction)
DECLARE_EXCEPTION_CLASS(noncontinuable_exception)
DECLARE_EXCEPTION_CLASS(stack_overflow)
DECLARE_EXCEPTION_CLASS(invalid_disposition)
DECLARE_EXCEPTION_CLASS(guard_page)
DECLARE_EXCEPTION_CLASS(invalid_handle)
DECLARE_EXCEPTION_CLASS(microsoft_cpp)
Оригинальный класс исходил из этой очень полезной статьи:
Такое нарушение означает, что в коде есть что-то серьезное, и это ненадежно. Я вижу, что программа может захотеть сохранить данные пользователя таким образом, что, как надеются, не будет писать предыдущие данные, в надежде, что данные пользователя еще не повреждены, но по определению нет стандартного метода борьбы с неопределенным поведением.
Прочитайте его и плачьте!
Я понял это. Если вы не выбрасываете из обработчика, обработчик будет просто продолжать, и это будет исключение.
Магия происходит, когда вы бросаете свое собственное исключение и обрабатываете это.
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <tchar.h>
void SignalHandler(int signal)
{
printf("Signal %d",signal);
throw "!Access Violation!";
}
int main()
{
typedef void (*SignalHandlerPointer)(int);
SignalHandlerPointer previousHandler;
previousHandler = signal(SIGSEGV , SignalHandler);
try{
*(int *) 0 = 0;// Baaaaaaad thing that should never be caught. You should write good code in the first place.
}
catch(char *e)
{
printf("Exception Caught: %s\n",e);
}
printf("Now we continue, unhindered, like the abomination never happened. (I am an EVIL genius)\n");
printf("But please kids, DONT TRY THIS AT HOME ;)\n");
}
Этот тип ситуации зависит от реализации, и поэтому для ее ловушки потребуется конкретный механизм поставщика. С Microsoft это будет связано с SEH, а * nix будет включать в себя сигнал
. В целом, хотя исключение исключения доступа является очень плохой идеей. Существует почти нет возможности восстановить из AV-исключения, и попытка сделать это просто приведет к сложному обнаружению ошибок в вашей программе.
Не механизм обработки исключений, но вы можете использовать механизм signal (), который предоставляется C.
> man signal
11 SIGSEGV create core image segmentation violation
Запись на NULL-указатель, вероятно, вызовет сигнал SIGSEGV
По крайней мере, для меня подход signal(SIGSEGV ...)
, упомянутый в другом ответе, не работал на Win32 с Visual C ++ 2015. Что сделал для меня, было использовать _set_se_translator()
, найденный в eh.h
, Он работает следующим образом:
Шаг 1) Убедитесь, что вы включили Да с исключениями SEH (/ EHa) в Свойства проекта / С ++ / Генерация кода / Включить исключения C ++ , как указано в ответ Владимир Фрицкий .
Шаг 2) Вызовите _set_se_translator()
, передав указатель функции (или лямбда) для нового исключения translator . Он называется переводчиком, потому что он в основном просто берет исключение низкого уровня и перебрасывает его как нечто более легкое для захвата, например std::exception
:
#include <string>
#include <eh.h>
// Be sure to enable "Yes with SEH Exceptions (/EHa)" in C++ / Code Generation;
_set_se_translator([](unsigned int u, EXCEPTION_POINTERS *pExp) {
std::string error = "SE Exception: ";
switch (u) {
case 0xC0000005:
error += "Access Violation";
break;
default:
char result[11];
sprintf_s(result, 11, "0x%08X", u);
error += result;
};
throw std::exception(error.c_str());
});
Шаг 3) Поймать исключение, как вы обычно:
try{
MakeAnException();
}
catch(std::exception ex){
HandleIt();
};
Существует очень простой способ поймать любое исключение (деление на ноль, нарушение прав доступа и т. д.) в Visual Studio с помощью try -> catch (...). Достаточно небольшой настройки настроек проекта. Просто включите / EHa в настройках проекта. См. «Свойства проекта» -> C / C ++ -> Генерация кода -> Изменить исключения Enable C ++ на «Да с исключениями SEH». Вот и все!
См. Подробности здесь: http://msdn.microsoft.com/en-us/library/1deeycx5 (v = vs.80) .aspx