Ant*_*lix 5 python inheritance enums python-3.x python-3.6
我正在尝试重载__init__()枚举子类的方法。奇怪的是,适用于普通类的模式不再适用于 Enum。
下面显示了使用普通类的所需模式:
class Integer:
def __init__(self, a):
"""Accepts only int"""
assert isinstance(a, int)
self.a = a
def __repr__(self):
return str(self.a)
class RobustInteger(Integer):
def __init__(self, a):
"""Accepts int or str"""
if isinstance(a, str):
super().__init__(int(a))
else:
super().__init__(a)
print(Integer(1))
# 1
print(RobustInteger(1))
# 1
print(RobustInteger('1'))
# 1
Run Code Online (Sandbox Code Playgroud)
如果与 Enum 一起使用,则相同的模式会中断:
from enum import Enum
from datetime import date
class WeekDay(Enum):
MONDAY = 0
TUESDAY = 1
WEDNESDAY = 2
THURSDAY = 3
FRIDAY = 4
SATURDAY = 5
SUNDAY = 6
def __init__(self, value):
"""Accepts int or date"""
if isinstance(value, date):
super().__init__(date.weekday())
else:
super().__init__(value)
assert WeekDay(0) == WeekDay.MONDAY
assert WeekDay(date(2019, 4, 3)) == WeekDay.MONDAY
# ---------------------------------------------------------------------------
# TypeError Traceback (most recent call last)
# /path/to/my/test/file.py in <module>()
# 27
# 28
# ---> 29 class WeekDay(Enum):
# 30 MONDAY = 0
# 31 TUESDAY = 1
# /path/to/my/virtualenv/lib/python3.6/enum.py in __new__(metacls, cls, bases, classdict)
# 208 enum_member._name_ = member_name
# 209 enum_member.__objclass__ = enum_class
# --> 210 enum_member.__init__(*args)
# 211 # If another member with the same value was already defined, the
# 212 # new member becomes an alias to the existing one.
# /path/to/my/test/file.py in __init__(self, value)
# 40 super().__init__(date.weekday())
# 41 else:
# ---> 42 super().__init__(value)
# 43
# 44
# TypeError: object.__init__() takes no parameters
Run Code Online (Sandbox Code Playgroud)
你必须使_missing_钩子过载。的所有实例WeekDay都是在第一次定义类时创建的;WeekDay(date(...))是索引操作而不是创建操作,并且__new__最初查找绑定到整数 0 到 6 的预先存在的值。如果失败,它会调用_missing_,您可以在其中将date对象转换为这样的整数。
class WeekDay(Enum):
MONDAY = 0
TUESDAY = 1
WEDNESDAY = 2
THURSDAY = 3
FRIDAY = 4
SATURDAY = 5
SUNDAY = 6
@classmethod
def _missing_(cls, value):
if isinstance(value, date):
return cls(value.weekday())
return super()._missing_(value)
Run Code Online (Sandbox Code Playgroud)
几个例子:
>>> WeekDay(date(2019,3,7))
<WeekDay.THURSDAY: 3>
>>> assert WeekDay(date(2019, 4, 1)) == WeekDay.MONDAY
>>> assert WeekDay(date(2019, 4, 3)) == WeekDay.MONDAY
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
Run Code Online (Sandbox Code Playgroud)
(注意:_missing_在 Python 3.6 之前不可用。)
在 3.6 之前,您似乎可以覆盖EnumMeta.__call__以进行相同的检查,但我不确定这是否会产生意想不到的副作用。(推理__call__总是让我头晕。)
# Silently convert an instance of datatime.date to a day-of-week
# integer for lookup.
class WeekDayMeta(EnumMeta):
def __call__(cls, value, *args, **kwargs):
if isinstance(value, date):
value = value.weekday())
return super().__call__(value, *args, **kwargs)
class WeekDay(Enum, metaclass=WeekDayMeta):
MONDAY = 0
TUESDAY = 1
WEDNESDAY = 2
THURSDAY = 3
FRIDAY = 4
SATURDAY = 5
SUNDAY = 6
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2289 次 |
| 最近记录: |