3

I wanted to make a python Enum work having a reserved word as member.

class Test(Enum):

    one = "one"
    is_ = "is"

I wanted to customize __name__ to have the usual syntax return

>>> print(Test.is_.name)
is

So how do I customize __name__, __getattribute__ or __getattr__ to accomplish this?

bad_coder
  • 11,289
  • 20
  • 44
  • 72

2 Answers2

2

It's stored in a single underscore variable:

>>> Test.is_._name_ = 'is'                                                                                                                                       
>>> Test.is_.name                                                                                                                                                
'is'

This will also fix up the repr's, and the call by member value still works:

>>> list(Test)                                                                                                                                                   
[<Test.one: 'one'>, <Test.is: 'is'>]
>>> Test('is')                                                                                                                                                   
<Test.is: 'is'>

Attribute access will still have to use the declared name, of course, because otherwise it would be a syntax error.

To enable call by member name, patch it into the map:

>>> Test.is_._name_ = 'is'                                                                                                                                       
>>> Test._member_map_['is'] = Test.is_                                                                                                                           
>>> Test['is']                                                                                                                                                   
<Test.is: 'is'>

If you need more than a simple alias here, then you might want to remove the original name and/or take care to preserve ordering in the member map.

wim
  • 338,267
  • 99
  • 616
  • 750
2

Instead of mucking about with the internals, you could use the Functional API instead:

Test = Enum('Test', [('one', 'one'), ('is', 'is'), ('is_', 'is')])

and in use:

>>> Test.one
<Test.one: 'one'>

>>> Test.is
  File "<stdin>", line 1
    test.is
          ^
SyntaxError: invalid syntax

>>> Test.is_
<Test.is: 'is'>

>>> Test['is']
<Test.is: 'is'>

>>> Test['is_']
<Test.is: 'is'>

>>> Test('is')
<Test.is: 'is'>

>>> list(Test)
[<Test.one: 'one'>, <Test.is: 'is'>]
Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
  • You are absolutely right @Ethan Furman I only remembered Functional API after having asked the question, because I always favor class syntax (when possible) in creating enum. – bad_coder Dec 17 '18 at 10:08