NameError при использовании super () в конструкторе enum - PullRequest
0 голосов
/ 26 июня 2018

Я использую Python 2.7.10 с библиотекой enum34.Я пытаюсь сделать следующее:

from enum import Enum


class Foo(Enum):
    def __init__(self):
        pass


class Bar(Foo):
    VALUE = 1

    def __init__(self, value):
        super(Bar, self).__init__()

Когда этот код запускается, я получаю ошибку NameError: global name 'Bar' is not defined.Может ли кто-нибудь помочь объяснить, почему я получаю эту ошибку и можно ли вызвать родительский конструктор подкласса enum?Заранее спасибо!

Редактировать: обратная связь (с отредактированными путями) для Оливье Мелансона:

Traceback (most recent call last):
  File "/.../test.py", line 9, in <module>
    class Bar(Foo):
  File "/.../lib/python2.7/site-packages/enum/__init__.py", line 236, in __new__
    enum_member.__init__(*args)
  File "/.../test.py", line 13, in __init__
    super(Bar, self).__init__()
NameError: global name 'Bar' is not defined

Process finished with exit code 1

Ответы [ 2 ]

0 голосов
/ 24 июля 2019

Чтобы обойти проблему с именем Bar, еще не связанным с Bar Enum при создании его членов, используйте:

super(self.__class__, self).__init__()

(обратите внимание, что self.__class__занял место Bar)

0 голосов
/ 26 июня 2018

Проблема в том, что Bar.VALUE.__init__ вызывается до того, как Bar существует.

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

При этом этот код будет выдавать точно такую ​​же ошибку в 3.4+ с модулем stdlib enum и аналогичные ошибки при множественных заменах enum сторонних производителей.

В общем случае, если у вас есть Enumв иерархиях вообще, вы должны помещать значения только в «листовые» классы и поведение только в неконечные классы.Однако единственное ограничение, которое фактически задокументировано в Ограниченное наследование перечислений , - это отсутствие значений в неконечных классах, поэтому технически то, что вы пытаетесь сделать, должно быть законным, даже если это необычно и никогда не было явнопредназначен для работы.


Если вы использовали Python 3, есть довольно простой обходной путь: просто используйте super() вместо super(Bar, self), и это не имеет значения, чем Bar несуществует еще.

В Python 2, поскольку это невозможно, вам нужно вручную смоделировать super.Для полной общности это означает написание кода для обхода mro и т. Д., Но поскольку множественное наследование, включая два или более классов Enum, в любом случае не будет работать, вам будет достаточно просто статически его жестко кодировать:

def __init__(self, value):
    Foo.__init__(self)

В качестве альтернативы, если вы измените свой дизайн, чтобы поместить все поведение в неконечные классы, это также будет работать:

class Foo(Enum):
    def __init__(self):
        pass

class Bar(Foo):
    def __init__(self, value):
        super(Bar, self).__init__()

class Baz(Bar):
    VALUE = 1

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

...