While trying silly things to get my __str__
method working correctly on an Enum member, I discovered some behavior I don't really understand. I'm aware the following implementation is wrong, but I don't know why it does what it does.
Consider the following class:
from aenum import Enum, AutoValue
class MyEnum(str, Enum, settings=AutoValue, init="value data1 data2"):
__str__ = lambda self: self
def __new__(cls, name, *args, **kwargs):
member = str.__new__(cls)
member._value_ = name
return member
@staticmethod
def _generate_next_value_(name, *args, **kwargs):
return (name,) + args
member1 = 1, 2
member2 = 3, 4
On import, this works as exected. MyEnum.member1.data1 == 1
and MyEnum.member1.data2 == 2
. However, when I call str(MyEnum.member1)
an exception is thrown saying "missing value for 'data2'". I traced through the code here and it seems MyEnum.member1.__str__().__init__(MyEnum.member1.__str__())
is being called. I'm not positive that's the call path, but that's the result. And since MyEnum.__init__ is Enum.__init__
and we're using AutoValue, the init method is expecting two arguments. It's trying to set member1.data1 = member1
and member1.data2
doesn't have a value.
To be clear, I'm aware the correct solution is to implement the __str__
method as __str__ = str.__str__
. However, since isinstance(MyEnum.member1, str) == True
, and __str__
needs to return a str
... I'm unclear why the above implementation would behave how it does.
- Why is any
__init__
getting called? - Why is it insufficient to return
self
sinceself
is anstr
? - Unrelated somewhat, by why could I not implement this without setting "value"? If you take away, value from the init string, remove the
__new__
and_generate_next_value_
methods, on import aTypeError
is thrown sayingstr() argument 2 must be str, not int
(.../aenum/init.py:1302).
Calling
str
on an object behaves like calling any other type: it callsstr.__new__
on your object, and then if the result is an instance ofstr
, it calls__init__
on the result.str.__new__
calls your__str__
method, which returns aMyEnum
. Since the return value is an instance ofstr
, the next step is to call the__init__
method. That's where the unexpected__init__
call is coming from.@user2357112 has the right of it.
To elaborate on your point:
self
is not astr
, it's aMyEnum
which is astr
subclass -- a subclass that has it's own__init__
, which then gets called. Thestr
class does not have an__init__
method.