Python 将自定义生成器添加到spaCy';s级

Python 将自定义生成器添加到spaCy';s级,python,class,generator,spacy,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

我很难在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在其自身中使用了
@property
,并且工作正常。这里的问题是什么?

出于我还不理解的原因,去掉
@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']
def字母_生成器(自身):
对于self.text中的x:
产量x
spacy.tokens.token.token.set_扩展名('letters',getter=letter\u生成器,force=True)
doc=nlp(“你好,世界”)
打印(键入(文件[0]。uu.字母))#
[0]号文件中的x代表x.[字母]#['H','e','l','l','o']

在您的通用示例中,您通过class属性访问属性,这意味着描述符协议被触发

另一方面,
set\u extension
,只需将对
属性
对象的引用保存在
dict
中,这意味着当您访问它时,描述符协议不会被触发,您会得到
属性本身,而不是getter的结果


在您的解决方案中,您根本不使用属性,因此您直接获得生成器函数。

好吧,
默认
属性是当既没有设置
getter
也没有设置
setter
时返回的值,因此这就是返回的值(如果删除
属性
decorator,则返回属性或函数)。您可以通过这种方式存储一些静态信息

您需要像在回答中那样设置
getter
,因为这是在您想要获取属性值时调用的操作<更改值时必须创建代码>设置器,如下所示:

doc[0]._.letters = "A"
setter
可以提供除
default
之外的其他值,尽管到目前为止我还没有使用这种方法

最后,我找到了一种扩展
spacy
的干净方法(我比前面介绍的方法可读性更好),例如
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)
如您所见,唯一需要使用的是
\uuu调用\uu
重载方法(不需要生成器,但也可以使用它,具体取决于任务的上下文)

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)