объект «функция» не имеет атрибута «значение», когда функция класса используется в значениях перечисления

#python #enums

Вопрос:

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

 class UserDefinedOperators:
    def not_contain(self, a, b):
            return a not in b
    def some_other_function(self, a, b):
            some other work here
 

Теперь я создаю перечисление, подобное этому

 import operator
import enum

class MyOperators(enum.Enum):
    LT = operator.gt
    GT = operator.gt
    NOT_CONTAIN = UserDefinedOperators().not_contain
 

У меня есть следующие различия в доступе к значению перечисления

 >>> MyOperators
<enum 'MyOperators'>
>>> MyOperators.LT
<MyOperators.LT: <built-in function gt>>
>>> MyOperators.LT.value
<built-in function gt>
>>> MyOperators.LT.name
'LT'
>>> MyOperators.NOT_CONTAIN
<bound method UserDefinedOperators.not_contain of <__main__.UserDefinedOperators object at 0x100cdbeb0>>
>>> MyOperators.NOT_CONTAIN.value
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute 'value'
>>> MyOperators.NOT_CONTAIN.name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute 'name'
>>> 
 

Таким образом, в функции класса перечисление показывает

 AttributeError: 'function' object has no attribute 'value'
 

Я прочитал в другом ответе SO, что он присваивается как функция, а не атрибуты перечисления, поэтому у него нет .value .name атрибутов или. Но тогда встроенный operator.lt и operator.gt также является функцией, тогда почему он работает нормально и имеет свойства .value и .name?

Ошибка действительно связана с нормальной функцией, а не только с функцией класса, но я хочу понять, в чем разница в модуле оператора? Как я могу добиться того же в своем классе?

Ответ №1:

Перечисление использует наличие __dunder__ метода __get__ для определения того, является ли объект функцией/классом. У всех функций и классов, созданных в Python, есть __get__ метод, но у встроенных функций его нет.

Чтобы обойти эту проблему, вы можете использовать модуль aenum 1 и его member функцию:

 from aenum import Enum, member
import operator

class UserDefinedOperators:
    #
    @staticmethod
    def not_contain(self, a, b):
            return a not in b


class MyOperators(Enum):
    LT = operator.lt
    GT = operator.gt
    NOT_CONTAIN = member(UserDefinedOperators.not_contain)
 

и в использовании

 >>> list(MyOperators)
[
  <MyOperators.LT: <built-in function lt>>,
  <MyOperators.GT: <built-in function gt>>,
  <MyOperators.NOT_CONTAIN: <function UserDefinedOperators.not_contain at 0x7f9c875ed790>>,
  ]
 

Обратите внимание, что я заставил not_contain быть staticmethod А. Это уместно, поскольку not_contain методу не требуются данные ни экземпляра, ни класса для выполнения своей работы. Это также означает, что вам не нужно создавать экземпляр UserDefinedOperators с созданием элемента NOT_CONTAIN перечисления.


1 Раскрытие информации: Я являюсь автором Python stdlib Enum , enum34 бэкпорта и библиотеки расширенного перечисления ( aenum ).

Комментарии:

1. Я также отмечу, что класс, состоящий только из статических методов,-это просто наряженный словарь с функциями для значений.