我想将id
和phrase
的串联形式初始化type
from enum import Enum
from typing import NamedTuple
class WORD_TYPE(str, Enum):
APPROVED = 'approved'
FORBIDDEN = 'forbidden'
RISKY = 'risky'
class WordItem(NamedTuple):
phrase: str
type: WORD_TYPE
id: str = f'{phrase}_{type.name.lower()}'
因此,每次我指定phrase
和type
时,我都希望自动拥有一个id
。
word_item = WordItem(phrase='phrase', type=WORD_TYPE.FORBIDDEN)
asssert word_item.id == 'phrase_forbidden'
做到这一点的最佳方法是什么?也许有一些使用https://github.com/ericvsmith/dataclasses来做到这一点的方法?
答案 0 :(得分:2)
这是特殊方法__new__
应该解决的问题。不幸的是,NamedTuple
禁止在其定义内覆盖它。
但是您可以使用装饰器将其覆盖在定义之外:
def set_default(attr, func):
def set_new(typ):
old = typ.__new__
sig = inspect.signature(old)
def _new(cls, *args, **kwargs):
bound = sig.bind_partial(cls, *args, **kwargs).arguments
if not attr in bound:
bound[attr] = func(*args, **kwargs)
# print(bound) # uncomment for debug traces
return old(**bound)
typ.__new__ = _new
return typ
return set_new
@set_default('id', lambda phrase, typ: f'{phrase}_{typ.name.lower()}')
class WordItem(NamedTuple):
phrase: str
type: WORD_TYPE
id: str = None
然后您可以使用WordItem:
>>> w = WordItem('a', WORD_TYPE.APPROVED)
>>> w
WordItem(phrase='a', type=<WORD_TYPE.APPROVED: 'approved'>, id='a_approved')
>>> w2 = WordItem('b', WORD_TYPE.APPROVED, 'c')
>>> w2
WordItem(phrase='b', type=<WORD_TYPE.APPROVED: 'approved'>, id='c')
但是:
__new__
如果可以的话,应该避免这种技巧。它在我的3.6版本中可以正常工作,但可能会在以后的NamedTuple版本中中断,或者被本机实现所取代...
答案 1 :(得分:1)
您可以在__ init __方法内定义定义。像这样:
class WordItem(object):
... def __init__(self, first_name, last_name):
... self.full_name = f'{first_name}_{last_name}'
...
>>> word_item = WordItem('abc','xyz')
>>> assert word_item.full_name == 'abc_xyz'