将自定义生成器添加到spaCy的类

时间:2019-04-08 21:52:57

标签: python class generator 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方法(请参见documentation)。

@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在自己的code中使用@property,并且工作正常。这是什么问题?

3 个答案:

答案 0 :(得分:1)

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

您要像回答中那样设置getter,因为这是您要获取attribute值时调用的操作。更改值时必须创建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__重载方法(不需要生成器,但是您也可以使用它,具体取决于任务的上下文)。

答案 1 :(得分:0)

出于我尚未理解的原因,摆脱@property并使用getter关键字代替default是可行的。

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

spacy.tokens.token.Token.set_extension('letters', getter=letter_generator, force=True)
doc = nlp('Hello world')
print(type(doc[0]._.letters)) # <class 'generator'>
[x for x in doc[0]._.letters] # ['H', 'e', 'l', 'l', 'o']

答案 2 :(得分:0)

在您的一般示例中,您通过class属性访问该属性,这意味着描述符协议已触发。

另一方面,

set_extension仅将对property对象的引用保存在dict中,这意味着当您访问它时,描述符协议为 not < / em>触发,您将得到property本身,而不是获取方法的结果。

在解决方法中,您根本没有使用属性,因此您可以直接获取generator函数。