问题
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
selfsinceselfis 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 aTypeErroris thrown sayingstr() argument 2 must be str, not int(.../aenum/init.py:1302).
回答1:
Calling str on an object behaves like calling any other type: it calls str.__new__ on your object, and then if the result is an instance of str, it calls __init__ on the result.
str.__new__ calls your __str__ method, which returns a MyEnum. Since the return value is an instance of str, the next step is to call the __init__ method. That's where the unexpected __init__ call is coming from.
回答2:
@user2357112 has the right of it.
To elaborate on your point:
- Why is it insufficient to return
selfsinceselfis anstr?
self is not a str, it's a MyEnum which is a str subclass -- a subclass that has it's own __init__, which then gets called. The str class does not have an __init__ method.
来源:https://stackoverflow.com/questions/49518098/init-being-called-on-str-result-in-aenum-enum