首页 > 解决方案 > 将自定义生成器添加到 spaCy 的类

问题描述

我很难将生成器添加到 spaCy 的Token课程中​​。

首先,一个通用的 Python 相当于我正在尝试做的事情,它按预期工作。

class Foo:
    def __init__(self, n):
        self.n = n

@property
def lower_int_generator(self):
    x = 0
    while x < self.n:
        yield x
        x += 1

Foo.lower_ints = lower_int_generator
a = Foo(5)
print(type(a.lower_ints)) # <class 'generator'>
[x for x in a.lower_ints] # [0, 1, 2, 3, 4]

现在在 spaCy 中,它提供了一个set_extension方法(参见文档)。

@property
def letter_generator(self):
    for x in self.text:
        yield x

spacy.tokens.token.Token.set_extension('letters', default=letter_generator, force=True)
doc = nlp('Hello world')
print(type(doc[0]._.letters)) # <class 'property'>
[x for x in doc[0]._.letters] # TypeError: 'property' object is not iterable

值得注意的是,spaCy@property在它自己的代码中使用,它工作得很好。这里有什么问题?

标签: pythonclassgeneratorspacy

解决方案


好吧,default属性是既没有也没有设置时返回的值,因此这就是返回的值gettersetter如果删除property装饰器,则为属性或函数)。您可以通过这种方式存储一些静态信息。

您想像getter在回答中所做的那样进行设置,因为这是您想要获取属性值时调用的操作。setter更改值时必须创建,如下所示:

doc[0]._.letters = "A"

setter提供除 之外的其他值会很好default,尽管到目前为止我还没有使用过这种方法。

最后,我找到了一种干净的扩展方式spacy(并且 IMO 比所提供的更具可读性),lemmatization扩展示例:

class Lemmatizer:
    def __init__(self):
        self.lemmatizer = spacy.lemmatizer.Lemmatizer(
            spacy.lang.en.LEMMA_INDEX,
            spacy.lang.en.LEMMA_EXC,
            spacy.lang.en.LEMMA_RULES,
        )

    def __call__(self, token):
        corrected = token._.text
        if token.text == corrected:
            return token.lemma_
        return self.lemmatizer(corrected, token.pos_)[0]

spacy.tokens.Token.set_extension("lemma", getter=Lemmatizer(), force=True)

如您所见,唯一需要使用的是__call__重载方法(不需要生成器,但您也可以使用它,具体取决于您的任务上下文)。


推荐阅读