В Ubuntu в начале 2018 года нет python3.6-tk
в нормальных дистрибутивах ubuntu (xenial / 16.04), поэтому даже если у вас более ранние версии python-tk
, это не сработает.
My решение должно было использовать все с помощью python 3.5
:
sudo apt install python3.5-tk
virtualenv --python=`which python3.5` python-env
source python-env/bin/activate
pip install -r requirements.txt
И теперь matplotlib
может найти tkinter
.
EDIT:
I просто нужно было 3.6 afterall, а трюк был:
sudo apt install tk-dev
, а затем перестроить python3.6, после tk-dev
, например:
./configure
make
make install
Это - мое исходное сообщение, которое зажгло некоторые дебаты... , потому что это неправильно :
<час>оператор переключения не является тем же самым как большим если еще оператор. Каждый случай должен быть уникальным и оценен статически. Оператор переключения делает постоянное ответвление времени независимо от того, сколько случаев Вы имеете. Если еще оператор оценивает каждое условие, пока это не находит тот, который верен.
На самом деле, оператор переключения C# не всегда постоянное ответвление времени.
В некоторых случаях компилятор будет использовать оператор переключения CIL, который является действительно постоянным ответвлением времени с помощью таблицы переходов. Однако в редких случаях, как указано Ivan Hamilton компилятор может генерировать что-то еще полностью.
Это на самом деле довольно легко проверить путем записи различных операторов переключения C#, некоторые редкие, некоторые плотные, и рассмотрения получающегося CIL с инструментом ildasm.exe.
У меня нет фактически знания C#, но я подозреваю, что или переключатель был просто взят, как это происходит на других языках, не думая о создании, он более общий или разработчик решил, что расширение его не стоило того.
Строго говоря Вы абсолютно правы, что нет никакой причины поместить эти ограничения на него. Можно было бы подозревать, что причина состоит в том, что для позволенных случаев внедрение очень эффективно (как предложил Brian Ensink ( 44921 )), но я сомневаюсь, что внедрение очень эффективно (w.r.t. операторы "if"), если я использую целые числа и некоторые случайные случаи (например, 345,-4574 и 1234203). И в любом случае, что является вредом в разрешении его для всего (или по крайней мере больше) и говорящий, что это только эффективно для конкретных случаев (такой как (почти) последовательные числа).
я могу, однако, предположить, что можно было бы хотеть исключить типы из-за причин такой как один данный lomaxx ( 44918 ).
Редактирование: @Henk ( 44970 ): Если Строки будут максимально совместно использованы, то строки с равным содержанием будут указателями на ту же ячейку памяти также. Затем если можно удостовериться, что строки, используемые в случаях, хранятся последовательно в памяти, можно очень эффективно реализовать переключатель (т.е. с выполнением в порядке 2 выдерживает сравнение, дополнение и два перехода).
Я соглашаюсь с этот комментарий , что использование табличного подхода часто лучше.
В C# 1.0 это не было возможно, потому что он не имел дженериков и анонимных делегатов. Новые версии C# имеют леса для создания этой работы. Наличие нотации для литералов объектов, также помогает.
Я думаю, что Henk закрепил его с "никаким статическим доступом к системе типов" вещь
, Другая опция состоит в том, что нет никакого порядка к типам, где, поскольку численные данные и строки могут быть. Таким образом переключатель типа был бы, не может создать дерево двоичного поиска, просто линейный поиск.
записал:
"Оператор переключения делает постоянное ответвление времени независимо от того, сколько случаев Вы имеете".
, Так как язык позволяет строка тип использоваться в операторе переключения, который я предполагаю, компилятор не может сгенерировать код для постоянной реализации ответвления времени для этого типа и должен генерировать если затем стиль.
@mweerden - А-ч я вижу. Спасибо.
у меня нет большого опыта в C# и.NET, но кажется, что разработчики языка не предоставляют статический доступ к системе типов кроме узких обстоятельств. ключевое слово typeof возвращает объект, таким образом, это доступно во времени выполнения только.
Согласно документация оператора переключения , если будет однозначный способ неявно преобразовать объект в целочисленный тип, то это будет позволено. Я думаю, что Вы ожидаете поведение, где для каждого оператора выбора оно было бы заменено if (t == typeof(int))
, но это откроет целую кучу проблем, когда Вы доберетесь для перегрузки того оператора. Поведение изменилось бы, когда реализация детализирует для оператора переключения, измененного, если Вы записали Ваш == переопределение неправильно. Путем сокращения сравнений с целочисленными типами и строкой и теми вещами, которые могут быть уменьшены до целочисленных типов (и предназначаются к) они избегают потенциальных проблем.
Это не причина, почему, но спецификация C# разделяют 8.7.2 состояний следующее:
управляющий тип оператора переключения устанавливается выражением переключателя. Если тип выражения переключателя является sbyte, байтом, коротким, ushort, интервал, uint, долго, ulong, символ, строка или перечислимый тип, то это - управляющий тип оператора переключения. Иначе точно одно пользовательское неявное преобразование (В§6.4) должно существовать от типа выражения переключателя к одному из следующих возможных управляющих типов: sbyte, байт, короткий, ushort, интервал, uint, долго, ulong, символ, строка. Если никакое такое неявное преобразование не существует, или если больше чем одно такое неявное преобразование существует, ошибка времени компиляции происходит.
спецификация C# 3.0 расположена в: http://download.microsoft.com/download/3/8/8/388e7205-bc10-4226-b2a8-75351c669b09/CSharp%20Language%20Specification.doc
Я предполагаю, что нет никакой фундаментальной причины, почему компилятор не мог автоматически перевести Ваш оператор переключения в:
if (t == typeof(int))
{
...
}
elseif (t == typeof(string))
{
...
}
...
, Но нет очень получен этим.
оператор выбора А на целочисленных типах позволяет компилятору делать много оптимизации:
нет никакого дублирования (если Вы не копируете маркировки случая, которые компилятор обнаруживает). В Вашем примере t мог соответствовать нескольким типам из-за наследования. Первое должно соответствовать быть выполненным? Все они?
компилятор может принять решение реализовать оператор переключения по целочисленному типу таблицей переходов для предотвращения всех сравнений. При включении перечисления, которое имеет целочисленные значения от 0 до 100 затем, оно создает массив с 100 указателями в нем, один для каждого оператора переключения. Во времени выполнения это просто ищет адрес от массива на основе включаемого целочисленного значения. Это делает для намного лучшей производительности во время выполнения, чем выполнение 100 сравнений.
В то время как по теме, по словам Jeff Atwood, оператор переключения является злодеянием программирования . Используйте их экономно.
можно часто выполнять ту же задачу с помощью таблицы. Например:
var table = new Dictionary<Type, string>()
{
{ typeof(int), "it's an int!" }
{ typeof(string), "it's a string!" }
};
Type someType = typeof(int);
Console.WriteLine(table[someType]);
Между прочим, VB, имея ту же базовую архитектуру, позволяет намного более гибкий Select Case
операторы (вышеупомянутый код работал бы в VB), и все еще производит эффективный код, где это возможно, таким образом, аргумент techical ограничением нужно рассмотреть тщательно.
Главным образом те ограничения существуют из-за разработчиков языка. Базовое выравнивание может быть совместимостью с languange историей, идеалами или упрощением дизайна компилятора.
компилятор может (и делать), примите решение:
оператор переключения НЕ ЯВЛЯЮТСЯ постоянным ответвлением времени. Компилятор может найти ярлыки (использующий блоки хеша, и т.д.), но более сложные случаи сгенерируют более сложный код MSIL с некоторыми случаями, расширяющимися ранее, чем другие.
Для обработки Строкового случая компилятор закончит тем (в какой-то момент), что использовал a. Равняется (b) (и возможно a. GetHashCode ()). Я думаю, что это был бы trival для компилятора для использования любого объекта, который удовлетворяет эти ограничения.
Что касается потребности в статических case-выражениях... некоторые из тех оптимизаций (хеширование, кэширование, и т.д.) не были бы доступны, если бы case-выражения не были детерминированы. Но мы уже видели, что иногда компилятор просто выбирает упрощенную if-else-if-else дорогу так или иначе...
Редактирование: lomaxx - Ваше понимание "typeof" оператора не корректно. "typeof" оператор используется для получения Системы. Текстовый объект для типа (ничто, чтобы сделать с его супертипами или интерфейсами). Проверка совместимости во время выполнения объекта с данным типом "," задание оператора. Использование "typeof" здесь для выражения объекта не важно.
Первая причина, которая приходит на ум, историческая :
Начиная с большей части C, C++ и программисты Java не приучены к наличию таких свобод, они не требуют их.
Другой, более допустимый, причина - то, что сложность языка увеличилась бы :
, В первую очередь, объекты должны быть по сравнению с .Equals()
или с ==
оператор? Оба допустимы в некоторых случаях. Мы должны представить новый синтаксис, чтобы сделать это? Мы должны позволить программисту представлять их собственный метод сравнения?
, Кроме того, позволяя включать объекты был бы предположения лежания в основе повреждения об операторе переключения . Существует два правила, управляющие оператором переключения, который компилятор не смог бы осуществить, если бы объектам позволили быть включенными (см. спецификация языка версии 3.0 C#, В§8.7.2):
Рассматривают этот пример кода в гипотетическом случае, который были позволены непостоянные значения случая:
void DoIt()
{
String foo = "bar";
Switch(foo, foo);
}
void Switch(String val1, String val2)
{
switch ("bar")
{
// The compiler will not know that val1 and val2 are not distinct
case val1:
// Is this case block selected?
break;
case val2:
// Or this one?
break;
case "bar":
// Or perhaps this one?
break;
}
}
, Что сделает код? Что, если операторы выбора переупорядочиваются? Действительно, одна из причин, почему C#, сделанный переключателем провалиться недопустимый, - то, что операторы переключения могли быть произвольно перестроены.
Эти правила существуют по причине - так, чтобы программист, путем рассмотрения одного блока случая, мог знать наверняка точное условие, при котором вводится блок. Когда вышеупомянутый оператор переключения превратится в 100 строк или больше (и он будет), такое знание неоценимо.
Важно не перепутать оператор переключения C# с инструкцией по переключателю CIL.
переключатель CIL является таблицей переходов, которая требует индекса в ряд адресов перехода.
Это только полезно, если случаи переключателя C# смежны:
case 3: blah; break;
case 4: blah; break;
case 5: blah; break;
, Но мало полезный, если они не:
case 10: blah; break;
case 200: blah; break;
case 3000: blah; break;
(Вам была бы нужна таблица ~3000 записи в размере только с 3 используемыми слотами)
С несмежными выражениями, компилятор может начать выполнять линейные if-else-if-else проверки.
С большим не - смежные наборы выражения, компилятор может запуститься с поиска двоичного дерева, и наконец if-else-if-else последние несколько объектов.
С наборами выражения, содержащими глыбы смежных объектов, компилятор может двоичное дерево искать, и наконец переключатель CIL.
Это полно "mays" & "силы", и это зависит от компилятора (может не согласиться с Моно или Ротором).
я копировал Ваши результаты на своей машине с помощью смежных случаев:
общее время для выполнения 10 путей переключатель, 10 000 повторений (мс): 25.1383
приблизительное время на 10 путей переключатель (мс): 0.00251383общее время для выполнения 50 путей переключатель, 10 000 повторений (мс): 26.593
приблизительное время на 50 путей переключатель (мс): 0.0026593общее время для выполнения 5 000 путей переключатель, 10 000 повторений (мс): 23.7094
приблизительное время на 5 000 путей переключатель (мс): 0.00237094общее время для выполнения 50 000 путей переключатель, 10 000 повторений (мс): 20.0933
приблизительное время на 50 000 путей переключатель (мс): 0.00200933
Затем я также сделал использующие несмежные case-выражения:
общее время для выполнения 10 путей переключатель, 10 000 повторений (мс): 19.6189
приблизительное время на 10 путей переключатель (мс): 0.00196189общее время для выполнения 500 путей переключатель, 10 000 повторений (мс): 19.1664
приблизительное время на 500 путей переключатель (мс): 0.00191664общее время для выполнения 5 000 путей переключатель, 10 000 повторений (мс): 19.5871
приблизительное время на 5 000 путей переключатель (мс): 0.00195871А несмежные 50 000 операторов переключения случая не скомпилировали бы.
"Выражение является слишком длинным или сложным для компиляции рядом 'ConsoleApplication1. Программа. Основной (строка [])'
то, Что забавно здесь, то, что поиск двоичного дерева кажется немного (вероятно, не статистически) более быстрым, чем инструкция по переключателю CIL.
Brian, Вы использовали слово" постоянный ", который имеет очень определенное значение с вычислительной точки зрения теории сложности. В то время как упрощенный смежный целочисленный пример может произвести CIL, который считают O (1) (постоянный), редким примером является O (зарегистрируйте n) (логарифмические), кластеризованные примеры лежат где-нибудь, промежуточными, и небольшими примерами является O (n) (линейный).
Это даже не обращается к Строковой ситуации, в которой помехи Generic.Dictionary<string,int32>
могут быть созданы и перенесут определенные издержки на первом использовании. Производительность здесь будет зависеть от производительности Generic.Dictionary
.
, Если Вы проверяете Спецификация языка C# (не спецификация CIL) Вы найдете "15.7.2, оператор переключения" не упоминает о "постоянном времени" или что конкретная реализация даже использует инструкцию по переключателю CIL (очень остерегаться принятия таких вещей).
В конце дня, переключатель C# против целого выражения в современной системе является операцией подмикросекунды, и не обычно стоящий волнения о.
<час>, Конечно, эти времена будут зависеть от машин и условий. Я, о котором wouldn’t обращают внимание на эти тесты синхронизации, продолжительности микросекунды we’re говорящий, затмеваюсь любым выполняемым кодом “real” (и необходимо включать некоторый “real code” иначе, компилятор оптимизирует ответвление далеко), или дрожите в системе. Мои ответы основаны на использовании IL DASM для исследования CIL, созданного компилятором C#. Конечно, этот isn’t финал, как фактические инструкции выполнения ЦП затем создаются JIT.
я проверил заключительные инструкции ЦП, на самом деле выполняемые на моей x86 машине, и могу подтвердить простой смежный переключатель набора, делающий что-то как:
jmp ds:300025F0[eax*4]
, Где поиск двоичного дерева полон:
cmp ebx, 79Eh
jg 3000352B
cmp ebx, 654h
jg 300032BB
…
cmp ebx, 0F82h
jz 30005EEE
Я не вижу причин, по которым оператор switch должен соответствовать только статическому анализу
Верно, он не имеет , а многие языки делают фактически используйте операторы динамического переключения. Это означает, однако, что переупорядочение предложений case может изменить поведение кода.
За решениями по дизайну, которые вошли в "switch" здесь, есть некоторая интересная информация: Почему оператор switch C # разработан так, чтобы не разрешить провал, но все же требуется перерыв?
Разрешение динамических выражений case может привести к чудовищам, таким как этот код PHP:
switch (true) {
case a == 5:
...
break;
case b == 10:
...
break;
}
, который, откровенно говоря, должен просто использовать оператор if-else
.
Ответ Джуды выше натолкнул меня на идею. Вы можете "сымитировать" поведение переключателя OP выше, используя Dictionary
:
Dictionary<Type, Func<object, string, string>> typeTable = new Dictionary<Type, Func<object, string, string>>();
typeTable.Add(typeof(int), (o, s) =>
{
return string.Format("{0}: {1}", s, o.ToString());
});
Это позволит вам связать поведение с типом в том же стиле, что и оператор switch. Я полагаю, что при компиляции в IL у него есть дополнительное преимущество: вместо таблицы переходов в стиле switch он будет иметь ключ.