Тип ошибки инициализации данных обработки не определен перечислением связанных форматов файлов обмена

Обновлено: 06.07.2024

О до-диезе

Об этом учебнике по программированию на C Sharp

Если вы не знаете, является ли используемый вами объект типом значения или ссылочным типом, вы можете столкнуться с некоторыми неожиданностями. Например:

Как видите, объекты Point и Pen были созданы одинаково, но значение point1 осталось неизменным, когда новое значение координаты X было присвоено point2 , тогда как значение Pen1 было изменено, когда для pen2 был назначен новый цвет. Таким образом, мы можем вывести, что точки point1 и point2 содержат собственную копию объекта Point, тогда как pen1 и pen2 содержат ссылки на один и тот же объект Pen. Но как мы можем узнать это, не проведя этот эксперимент?

Ответ заключается в том, чтобы просмотреть определения типов объектов (что можно легко сделать в Visual Studio, поместив курсор на имя типа объекта и нажав F12):

Многие (но не все) типы значений имеют свойство IsEmpty, которое можно проверить, чтобы убедиться, что оно равно значению по умолчанию:

Когда вы проверяете, была ли переменная инициализирована или нет, убедитесь, что вы знаете, какое значение будет иметь неинициализированная переменная этого типа по умолчанию, и не полагайтесь на то, что она равна нулю..

Хотя многие программисты используют оператор == для сравнения строк, на самом деле это один из наименее желательных методов для использования, прежде всего потому, что он не указывает явно в коде, какой тип сравнения хотел.

Первая сигнатура метода (т. е. без параметра compareType) фактически аналогична использованию оператора ==, но имеет то преимущество, что она явно применяется к строкам. Он выполняет порядковое сравнение строк, которое в основном представляет собой побайтовое сравнение. Во многих случаях это именно тот тип сравнения, который вам нужен, особенно при сравнении строк, значения которых устанавливаются программно, таких как имена файлов, переменные среды, атрибуты и т. д. В этих случаях, если порядковое сравнение действительно является правильным типом сравнения в этой ситуации, единственным недостатком использования метода Equals без compareType является то, что кто-то, читающий код, может не знать, какой тип сравнения вы делаете.

Однако использование сигнатуры метода Equals, которая включает в себя compareType при каждом сравнении строк, не только сделает ваш код более понятным, но и заставит вас явно задуматься о том, какой тип сравнения вам нужно выполнить. Это стоит сделать, потому что даже если английский язык не может обеспечить много различий между порядковыми и учитывающими культуру сравнениями, другие языки предоставляют множество, и игнорирование возможностей других языков открывает перед вами большой потенциал для ошибки в пути. Например:

Самая безопасная практика — всегда указывать параметр compareType в методе Equals. Вот несколько основных рекомендаций:

  • При сравнении строк, которые были введены пользователем или должны отображаться пользователю, используйте сравнение с учетом языка и региональных параметров ( CurrentCulture или CurrentCultureIgnoreCase ).
  • При сравнении программных строк используйте порядковое сравнение ( Ordinal или OrdinalIgnoreCase ).
  • InvariantCulture и InvariantCultureIgnoreCase обычно не следует использовать, за исключением очень ограниченного числа случаев, поскольку порядковые сравнения более эффективны. Если необходимо сравнение с учетом культуры, его обычно следует выполнять с текущей культурой или другой конкретной культурой.

можно просто написать:

LINQ отлично подходит для абстрагирования задачи управления коллекциями, независимо от того, являются ли они объектами в памяти, таблицами базы данных или XML-документами. В идеальном мире вам не нужно было бы знать, что собой представляют лежащие в основе объекты. Но ошибка здесь в предположении, что мы живем в идеальном мире. На самом деле, одинаковые операторы LINQ могут возвращать разные результаты при выполнении с одними и теми же данными, если эти данные имеют другой формат.

Например, рассмотрим следующее утверждение:

Что произойдет, если один из объектов account.Status будет равен «Активный» (обратите внимание на заглавную букву А)? Ну, если бы myAccounts был объектом DbSet (который был настроен с конфигурацией по умолчанию без учета регистра), выражение where все равно соответствовало бы этому элементу. Однако если бы myAccounts находились в массиве в памяти, они бы не совпадали и, следовательно, давали бы другой общий результат.

Но подождите минутку. Когда мы говорили о сравнении строк ранее, мы видели, что оператор == выполняет порядковое сравнение строк. Так почему же в этом случае оператор == выполняет сравнение без учета регистра?

Как упоминалось ранее, операторы LINQ работают с любым объектом, который реализует IEnumerable. Например, следующая простая функция суммирует балансы на любом наборе счетов:

Ответ заключается в том, что Sum() не является методом, определенным в интерфейсе IEnumerable. Скорее, это статический метод (называемый «метод расширения»), определенный в классе System.Linq.Enumerable:

Так чем же метод расширения отличается от любого другого статического метода и что позволяет нам получить к нему доступ в других классах?

Отличительной характеристикой метода расширения является модификатор this в его первом параметре. Это «волшебство», которое идентифицирует его для компилятора как метод расширения. Тип параметра, который он изменяет (в данном случае IEnumerable ), обозначает класс или интерфейс, который затем появится для реализации этого метода.

(Кроме того, нет ничего волшебного в сходстве между именем интерфейса IEnumerable и именем класса Enumerable, для которого определен метод расширения. Это сходство — просто произвольный стилистический выбор.)

При таком понимании мы также можем видеть, что функцию sumAccounts, которую мы представили выше, можно было бы вместо этого реализовать следующим образом:

Даже разработчики, знакомые с методами расширения, все равно время от времени попадаются, когда в объекте есть метод с таким же именем, но его сигнатура метода слегка отличается от сигнатуры метода расширения. Много времени может быть потрачено впустую на поиск опечатки или ошибки, которой просто нет.

Конечно, вы также можете написать свои собственные методы расширения. Поймите, однако, что хотя кажется, что методы расширения вызываются точно так же, как и обычные методы экземпляра, на самом деле это всего лишь иллюзия. В частности, ваши методы расширения не могут ссылаться на закрытые или защищенные члены класса, который они расширяют, и поэтому не могут служить полной заменой более традиционному наследованию классов.

Хотя могут быть случаи, когда слишком много вариантов так же плохо, как и недостаточно, с объектами-коллекциями дело обстоит иначе. Количество доступных вариантов определенно может работать в вашу пользу. Потратьте немного больше времени заранее, чтобы изучить и выбрать оптимальный тип коллекции для ваших целей. Скорее всего, это повысит производительность и уменьшит вероятность ошибки.

Если существует тип коллекции, специально предназначенный для типа имеющегося у вас элемента (например, строка или бит), склоняйтесь к использованию его в первую очередь. Реализация, как правило, более эффективна, когда она нацелена на определенный тип элемента.

В среде CLR используется сборщик мусора, поэтому вам не нужно явно освобождать память, созданную для какого-либо объекта. На самом деле, вы не можете. В C нет эквивалента оператору удаления C++ или функции free(). Но это не значит, что вы можете просто забыть обо всех объектах после того, как закончили их использовать. Многие типы объектов инкапсулируют некоторые другие типы системных ресурсов (например, файл на диске, соединение с базой данных, сетевой сокет и т. д.). Если оставить эти ресурсы открытыми, общее количество системных ресурсов может быстро истощиться, что приведет к снижению производительности и, в конечном итоге, к сбоям программы.

Это не означает, что у финализаторов нет хороших применений, но детерминированное освобождение ресурсов не является одним из них. Скорее, когда вы работаете с файлом, сетью или подключением к базе данных, вы хотите явным образом освободить базовый ресурс, как только закончите с ним работать.

Создавая блок using в приведенном выше примере, вы точно знаете, что myFile.Dispose() будет вызываться, как только вы закончите работу с файлом, независимо от того, генерирует ли Read() исключение.

Самой очевидной ошибкой, которая может возникнуть при использовании метода 2, будет невозможность проверить возвращаемое значение. Это, вероятно, приведет к возможному исключению NullReferenceException, которое может появиться гораздо позже, что значительно усложнит отслеживание источника проблемы. В отличие от этого, метод 1 немедленно вызвал бы исключение InvalidCastException, что сделало бы источник проблемы более очевидным.

Более того, даже если вы не забудете проверить возвращаемое значение в методе 2, что вы будете делать, если обнаружите, что оно равно нулю? Подходит ли метод, который вы пишете, для сообщения об ошибке? Есть ли что-то еще, что вы можете попробовать, если этот состав не сработает? Если нет, то создание исключения является правильным решением, поэтому вы можете позволить этому произойти как можно ближе к источнику проблемы.

Вот несколько примеров других распространенных пар методов, где один генерирует исключение, а другой нет:

В качестве конкретного примера, если у вас есть альтернативное законное действие (например, действие по умолчанию), которое нужно предпринять, если было бы сгенерировано исключение, подход без исключений может быть законным выбором. В таком случае действительно может быть лучше написать что-то вроде этого:

Однако неверно предполагать, что TryParse обязательно является «лучшим» методом. Иногда это так, иногда нет. Вот почему есть два способа сделать это.Используйте правильный вариант для контекста, в котором вы находитесь, помня, что исключения, безусловно, могут быть вашими друзьями как разработчика.

Но если вы проигнорируете предупреждение такого типа, рано или поздно что-то вроде этого вполне может попасть в ваш код:

А с той скоростью, с которой Intellisense позволяет нам писать код, эта ошибка не так уж невероятна, как кажется.

Теперь у вас есть серьезная ошибка в вашей программе (хотя компилятор только пометил ее как предупреждение по уже объясненным причинам), и в зависимости от того, насколько сложна ваша программа, вы можете потратить много времени на ее отслеживание. вниз. Если бы вы обратили внимание на это предупреждение, вы бы избежали этой проблемы с помощью простого пятисекундного исправления.

Помните, что компилятор C Sharp предоставляет много полезной информации о надежности вашего кода… если вы слушаете. Не игнорируйте предупреждения. Обычно их исправление занимает всего несколько секунд, а исправление новых, когда они происходят, может сэкономить вам часы. Приучите себя ожидать, что в окне «Список ошибок» Visual Studio будет отображаться «0 ошибок, 0 предупреждений», чтобы любые предупреждения вызывали у вас достаточно дискомфорта, чтобы вы могли немедленно их устранить.

Подведение итогов

Дополнительная литература в блоге Toptal Engineering:

Понимание основ

перечисление — это отдельный тип, значение которого ограничено диапазоном значений (подробности см. ниже), который может включать несколько констант с явным именем ("перечислители" ). Значения констант являются значениями целочисленного типа, известного как базовый тип перечисления.

Перечисление (повторно) объявляется с использованием следующего синтаксиса:

аттрибут ключа-перечисления (необязательно) имя-заголовка-перечисления (необязательно) база-перечисления (необязательно)
список-перечисления (необязательно) >
(1)
enum-key attr (необязательно) enum-head-name (необязательно) enum-base (необязательно)
enumerator-list , >
(2)
enum-key attr (необязательно) enum-head-name enum-base (необязательно) ; (3) (начиная с C++11)

1) enum-specifier, который появляется в decl-specifier-seq синтаксиса объявления: определяет тип перечисления и его перечислители.

3) Непрозрачное объявление перечисления: определяет тип перечисления, но не его перечислители: после этого объявления тип является полным типом, и его размер известен. Примечание: явное объявление специализации члена перечисления с ограниченной областью действия шаблона класса — это единственный случай, когда спецификатор вложенного имени появляется перед именем перечисления.

один из enum , enum class или enum struct

имя объявляемого перечисления, его можно не указывать.

имя объявляемого перечисления, которому может предшествовать спецификатор вложенного имени : последовательность имен и операторов разрешения области :: , заканчивающаяся оператором разрешения области. Его можно опустить только в непрозрачных объявлениях перечисления с незаданной областью. спецификатор вложенного имени может появиться только в том случае, если присутствует имя перечисления и это объявление является повторным объявлением.

Существует два различных вида перечислений: перечисление с незаданной областью (объявлено с помощью enum-key enum ) и перечисление с областью действия (объявлено с помощью класса перечисления enum-key или enum структура).

Содержание

[править] Перечисления без области действия

имя перечисления (необязательно) enumerator = constexpr , enumerator = constexpr , . > (1)
имя перечисления (необязательно): type enumerator = constexpr , enumerator = constexpr , . > (2) (начиная с C++11)
enum name : type ; (3) (начиная с C++11)

1) Объявляет тип перечисления с незаданной областью, базовый тип которого не является фиксированным (в этом случае базовый тип является определяемым реализацией целочисленным типом, который может представлять все значения перечислителя; этот тип не больше, чем int, если только значение перечислитель не может поместиться в int или unsigned int Если список перечислителей пуст, базовый тип таков, как если бы перечисление имело один перечислитель со значением 0. Если ни один целочисленный тип не может представить все значения перечислителя, перечисление плохо- сформировано).

3) Объявление непрозрачного перечисления для перечисления с незаданной областью должно указывать имя и базовый тип.

Каждый перечислитель становится именованной константой типа перечисления (т. е. name ), видимой в окружающей области и может использоваться всякий раз, когда требуются константы.

Каждый перечислитель связан со значением базового типа. Когда в списке перечислителей указаны инициализаторы, значения перечислителей определяются этими инициализаторами. Если у первого перечислителя нет инициализатора, связанное значение равно нулю. Для любого другого перечислителя, в определении которого нет инициализатора, связанное значение равно значению предыдущего перечислителя плюс один.

Значения типа перечисления с незаданной областью можно неявно преобразовать в целочисленные типы. Если базовый тип не является фиксированным, значение преобразуется в первый тип из следующего списка, который может содержать весь диапазон значений: int, unsigned int, long, unsigned long, long long или unsigned long long, расширенные целые типы с более высокий ранг преобразования (в порядке ранжирования, знаковый предпочтительнее беззнакового) (начиная с C++11) . Если базовый тип является фиксированным, значения можно преобразовать в базовый тип (предпочтительно при разрешении перегрузки), который затем можно повысить.

Значения целых чисел, чисел с плавающей запятой и перечисляемых типов можно преобразовать с помощью static_cast или явного приведения в любой перечисляемый тип. Если базовый тип не фиксирован, а исходное значение выходит за пределы допустимого диапазона, поведение не определено. (Исходное значение, преобразованное в базовый тип перечисления, если оно представляет собой число с плавающей запятой, находится в диапазоне, если оно помещается в наименьшее битовое поле, достаточно большое, чтобы вместить все перечислители целевого перечисления.) В противном случае результат совпадает с результатом результат неявного преобразования в базовый тип.

Обратите внимание, что значение после такого преобразования может не обязательно равняться любому из именованных перечислителей, определенных для перечисления.

Имя перечисления без области может быть опущено: такое объявление только вводит перечислители в охватывающую область:

Если перечисление с незаданной областью является членом класса, доступ к его перечислителям можно получить с помощью операторов доступа к членам класса. и -> :

[править] Перечисления с областью действия

enum struct|имя класса enumerator = constexpr , enumerator = constexpr , . > (1)
enum struct|имя класса: type enumerator = constexpr, enumerator = constexpr, . > (2)
enum struct|имя класса ; (3)
enum struct|имя класса: тип; (4)

1) объявляет тип перечисления с ограниченной областью действия, базовым типом которого является int (ключевые слова class и struct полностью эквивалентны)

Каждый перечислитель становится именованной константой типа перечисления (т. е. name ), которая содержится в области действия перечисления и может быть доступна с помощью оператора разрешения области. Неявные преобразования значений перечислителя с областью действия в целочисленные типы отсутствуют, хотя для получения числового значения перечислителя можно использовать static_cast.

Перечисление можно инициализировать из целого числа без приведения, используя инициализацию списка, если выполняются все следующие условия:

  • инициализация — это прямая-списковая-инициализация
  • список инициализаторов содержит только один элемент
  • перечисление либо с ограниченной областью действия, либо без нее с фиксированным базовым типом
  • конверсия не сужает

Это позволяет вводить новые целочисленные типы (например, SafeInt), которые пользуются теми же существующими соглашениями о вызовах, что и лежащие в их основе целочисленные типы, даже в ABI, которые штрафуют передачу/возврат структур по значению.

Использование объявления перечисления

с использованием enum спецификатора вложенного имени (необязательно) name ; (начиная с C++20)

где имя спецификатора вложенного имени (необязательно) не должно называть зависимый тип и должно называть тип перечисления.

Объявление-использования-перечисления вводит имена перечислителей именованного перечисления, как если бы посредством объявления-использования для каждого перечислителя. В области класса объявление using-enum добавляет перечислители именованного перечисления в качестве членов в область действия, делая их доступными для поиска элементов.

Два объявления using-enum, вводящие два перечислителя с одинаковым именем, конфликтуют.

[править] Примечания

Хотя преобразование из перечисления вне диапазона в перечисление без фиксированного базового типа стало неопределенным поведением в соответствии с решением проблемы CWG 1766, в настоящее время ни один компилятор не выполняет для него требуемую диагностику при постоянной оценке.

Перечисление — это набор символических имен (элементов), связанных с уникальными постоянными значениями. В перечислении элементы можно сравнивать по идентичности, а само перечисление можно повторять.

Случай членов Enum

Поскольку Enums используются для представления констант, мы рекомендуем использовать имена UPPER_CASE для членов перечисления и будем использовать этот стиль в наших примерах.

Содержимое модуля¶

Этот модуль определяет четыре класса перечисления, которые можно использовать для определения уникальных наборов имен и значений: Enum , IntEnum , Flag и IntFlag . Он также определяет один декоратор, unique() , и один помощник, auto .

Базовый класс для создания перечислимых констант. См. раздел Функциональный API для альтернативного синтаксиса конструкции.

Перечисление

класса. IntEnum ¶

Базовый класс для создания перечислимых констант, которые также являются подклассами int .

Перечисление

класса. IntFlag ¶

Базовый класс для создания перечисляемых констант, которые можно комбинировать с помощью побитовых операторов без потери их членства в IntFlag. Члены IntFlag также являются подклассами int .

Базовый класс для создания перечислимых констант, которые можно комбинировать с помощью побитовых операций без потери принадлежности к флагу.

Декоратор класса Enum, обеспечивающий привязку только одного имени к любому значению.

Экземпляры заменяются соответствующими значениями для элементов Enum. По умолчанию начальное значение начинается с 1.

Новое в версии 3.6: Flag , IntFlag , auto

Создание перечисления¶

Перечисления создаются с использованием синтаксиса класса, что упрощает их чтение и запись. Альтернативный метод создания описан в Functional API. Чтобы определить перечисление, создайте подкласс Enum следующим образом:

Значения членов перечисления

Значения членов могут быть любыми: int , str и т. д. Если точное значение не имеет значения, вы можете использовать автоматические экземпляры, и для вас будет выбрано подходящее значение. Следует соблюдать осторожность, если вы смешиваете auto с другими значениями.

Класс Color является перечислением (или перечислением)

Атрибуты Color.RED , Color.GREEN и т. д. – это члены перечисления (или члены перечисления) и функционально константы.

Элементы перечисления имеют имена и значения (имя Color.RED — RED , значение Color.BLUE — 3 и т. д.)

Несмотря на то, что мы используем синтаксис класса для создания перечислений, перечисления не являются обычными классами Python. См. Чем отличаются перечисления? для более подробной информации.

Элементы перечисления имеют удобочитаемые строковые представления:

…пока в их представлении есть дополнительная информация:

Тип члена перечисления – это перечисление, которому он принадлежит:

Элементы Enum также имеют свойство, содержащее только название их элемента:

Перечисления поддерживают итерацию в порядке определения:

Члены перечисления можно хэшировать, поэтому их можно использовать в словарях и наборах:

Программный доступ к элементам перечисления и их атрибутам¶

Иногда полезно обращаться к членам в перечислениях программно (например, в ситуациях, когда Color.RED не подходит, поскольку точный цвет неизвестен во время написания программы). Enum разрешает такой доступ:

Если вы хотите получить доступ к элементам перечисления по имени, используйте доступ к элементам:

Если у вас есть элемент перечисления и вам нужно его имя или значение:

Дублирование членов и значений перечисления¶

Недопустимо наличие двух членов перечисления с одинаковыми именами:

Однако два члена перечисления могут иметь одно и то же значение. Учитывая два члена A и B с одинаковым значением (и A определен первым), B является псевдонимом для A. Поиск по значению значения A и B вернет A. Поиск по имени B также вернет A:

Попытка создать элемент с тем же именем, что и у уже определенного атрибута (другой элемент, метод и т. д.), или попытка создать атрибут с тем же именем, что и у члена, не допускается.

Обеспечение уникальных значений перечисления¶

По умолчанию перечисления позволяют использовать несколько имен в качестве псевдонимов для одного и того же значения. Если такое поведение нежелательно, можно использовать следующий декоратор, чтобы убедиться, что каждое значение используется только один раз в перечислении:

Декоратор класса специально для перечислений. Он ищет __members__ перечисления, собирая все найденные псевдонимы; если таковые обнаружены, возникает ошибка ValueError с подробностями:

Использование автоматических значений¶

Если точное значение не имеет значения, вы можете использовать auto :

Значения выбираются функцией _generate_next_value_() , которую можно переопределить:

Целью метода _generate_next_value_() по умолчанию является предоставление следующего int в последовательности с последним предоставленным int, но то, как это делается, зависит от реализации и может измениться.

Метод _generate_next_value_() должен быть определен до любых членов.

Итерация¶

Перебор членов перечисления не дает псевдонимов:

Специальный атрибут __members__ представляет собой доступное только для чтения упорядоченное сопоставление имен с членами. Он включает все имена, определенные в перечислении, включая псевдонимы:

Атрибут __members__ можно использовать для подробного программного доступа к членам перечисления. Например, поиск всех псевдонимов:

Сравнения¶

Элементы перечисления сравниваются по идентификатору:

Упорядоченные сравнения между значениями перечисления не поддерживаются. Элементы Enum не являются целыми числами (но см. IntEnum ниже):

Однако определены сравнения равенства:

Сравнения со значениями, не относящимися к перечислению, всегда будут сравнивать не равные (опять же, IntEnum был специально разработан для того, чтобы вести себя иначе, см. ниже):

Разрешенные члены и атрибуты перечислений¶

В приведенных выше примерах в качестве значений перечисления используются целые числа. Использование целых чисел является коротким и удобным (и предоставляется по умолчанию функциональным API), но строго не соблюдается.В подавляющем большинстве случаев использования не важно, каково фактическое значение перечисления. Но если значение важно, перечисления могут иметь произвольные значения.

Перечисления — это классы Python, которые, как обычно, могут иметь методы и специальные методы. Если у нас есть это перечисление:

Разрешенные правила следующие: имена, начинающиеся и заканчивающиеся символом подчеркивания, зарезервированы перечислением и не могут использоваться; все другие атрибуты, определенные в перечислении, станут членами этого перечисления, за исключением специальных методов ( __str__() , __add__() и т. д.), дескрипторов (методы также являются дескрипторами) и имен переменных, перечисленных в _ignore_ .

Примечание: если ваше перечисление определяет __new__() и/или __init__(), то любое значение(я), переданное члену перечисления, будет передано в эти методы. Пример см. в разделе "Планета".

Ограниченное создание подклассов Enum¶

Новый класс Enum должен иметь один базовый класс Enum, до одного конкретного типа данных и столько объектов-примесей, сколько необходимо. Порядок этих базовых классов:

Кроме того, создание подкласса перечисления разрешено только в том случае, если перечисление не определяет никаких членов. Итак, это запрещено:

Но это разрешено:

Разрешение создания подклассов перечислений, определяющих члены, приведет к нарушению некоторых важных инвариантов типов и экземпляров. С другой стороны, имеет смысл разрешить совместное поведение группы перечислений. (См. пример OrderedEnum.)

Травление¶

Перечисления могут быть выделены и удалены:

Применяются обычные ограничения для выделения: перечисления, допускающие выборку, должны быть определены на верхнем уровне модуля, поскольку для распаковки требуется, чтобы их можно было импортировать из этого модуля.

Протокол pickle версии 4 позволяет легко обрабатывать перечисления, вложенные в другие классы.

Можно изменить способ выбора/отключения элементов Enum, определив __reduce_ex__() в классе перечисления.

Функциональный API¶

Класс Enum можно вызывать, предоставляя следующий функциональный API:

Семантика этого API напоминает namedtuple . Первым аргументом вызова Enum является имя перечисления.

Второй аргумент — это источник имен элементов перечисления. Это может быть строка имен, разделенных пробелами, последовательность имен, последовательность двух кортежей с парами ключ/значение или сопоставление (например, словарь) имен со значениями. Последние две опции позволяют присваивать перечислениям произвольные значения; другие автоматически назначают возрастающие целые числа, начиная с 1 (используйте параметр start, чтобы указать другое начальное значение). Возвращается новый класс, производный от Enum. Другими словами, указанное выше присвоение Animal эквивалентно следующему:

Причина использования по умолчанию 1 в качестве начального числа, а не 0, заключается в том, что 0 является False в логическом смысле, но все члены перечисления оцениваются как True .

Выбор перечислений, созданных с помощью функционального API, может оказаться сложной задачей, поскольку сведения о реализации стека фреймов используются, чтобы попытаться выяснить, в каком модуле создается перечисление (например, если вы используете вспомогательную функцию в отдельном модуле, может не работать на IronPython или Jython). Решение состоит в том, чтобы явно указать имя модуля следующим образом:

Если модуль не указан, а Enum не может определить, что это такое, новые элементы Enum не будут доступны для выбора; чтобы ошибки оставались ближе к источнику, травление будет отключено.

Новый протокол pickle 4 также в некоторых случаях полагается на то, что __qualname__ устанавливается в место, где pickle сможет найти класс. Например, если класс был сделан доступным в классе SomeData в глобальной области:

Полная подпись:

Что новый класс Enum будет записывать в качестве своего имени.

Члены Enum. Это может быть строка, разделенная пробелами или запятыми (значения начинаются с 1, если не указано иное):

Читайте также: