'Python derived enum missing required positional argument
I'm trying to define an object-valued enum, and I'm running in an error of "missing 1 required positional argument" in enum_member.__init__(*args)
A basic example of my code, following the documentation from enum, let's call it problem.py
which is imported in upper.py
import enum
class test(object):
def __init__(self, par1, par2):
# do stuff with the parameters and assign to object fields
# more object methods
class testlist(test, enum.Enum):
A = test(1,2)
B = test(3,4),
# a few more of these
When importing the module in which these classes are defined, I get the following error (edited to match the example):
File "upper.py", line 14, in <module>
from problem import test
File "problem.py", line 75, in <module>
class testlist(test, enum.Enum):
File "/usr/lib/python3.8/enum.py", line 252, in __new__
enum_member.__init__(*args)
TypeError: __init__() missing 1 required positional argument: 'par2'
I'm guessing that I'm misunderstanding how derived enums work, but from the documentation I can't figure out how I'm missing an argument.
(edit)
The goal is to have testlist
values behave as test
objects, which also define a few methods and override arithmetic operators, so I can do e.g., testlist.A + testlist.B
. The enum isn't strictly necessary, but it's convenient for iteration and groups the values better than having them as global variables in the module.
Solution 1:[1]
note that enum has its own way for __new__
and __init__
, in your case, you do not need to have test
as your parent class. if you do want, follow the documents https://docs.python.org/3/library/enum.html#when-to-use-new-vs-init
without test
class as your parent class, it will work
import enum
class test:
def __init__(self, par1, par2):
print(self, par1, par2)
class testlist(enum.Enum):
A = test(1, 2)
B = test(3, 4)
EDIT: below code to support + operator check the output to understand more how enum subclassing work.
import enum
class test(object):
def __init__(self, par1, par2):
print(self,':', par1, par2)
self.par1 = par1
self.par2 = par2
def __add__(self, rval):
print("test:", self, "+", rval)
class testlist(test, enum.Enum):
A = (1,2)
B = (3,4)
# a few more of these
def __new__(cls, par1, par2):
obj = object.__new__(cls)
obj._value_ = test(par1, par2)
return obj
def __init__(self, *args):
print(self.__class__, args)
# call __add__ of `testlist` if exist, otherwise __add__ of `test`
testlist.A + testlist.B
# value is `test` object
testlist.A.value + testlist.B.value
output
<__main__.test object at 0x7f112f1d7430> : 1 2
<enum 'testlist'> (1, 2)
<__main__.test object at 0x7f112f1f52e0> : 3 4
<enum 'testlist'> (3, 4)
test: testlist.A + testlist.B
test: <__main__.test object at 0x7f112f1d7430> + <__main__.test object at 0x7f112f1f52e0>
Solution 2:[2]
Aside: in your example of B = test(3,4),
that final comma should not be there.
What you are running into is that when you subclass another data type, whatever you assign to the member name will be passed to the subclassed type's __new__
and/or __init__
.
In other words, by inheriting from test
, your testlist
enum now has an __init__
that is expecting two arguments: one for par1
and one for par2
-- but you are only supplying one argument, e.g. test(1, 2)
. What you need to provide is simply 1, 2
:
class testlist(test, enum.Enum):
A = 1, 2
B = 3, 4
# a few more of these
In the above code the value for A
will be calculated by calling test(1, 2)
.
Another example that might help: int
can be called with two arguments, the first being a str
, and the second a base in which to interpret that string. So:
class Count(IntEnum):
ONE = 1 # value generated by int(1)
TWO = '2' # value generated by int('2')
THREE = '3', 10 # value generated by int('3', 10)
TEN = 'A', 16 # value generated by int('A', 16)
and when list
ed:
>>> list(Count)
[<Count.ONE: 1>, <Count.TWO: 2>, <Count.THREE: 3>, <Count.TEN: 10>]
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |