我很难在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
,并且工作正常。这是什么问题?
答案 0 :(得分:1)
好吧,default
属性是未设置getter
和setter
时返回的值,因此就是返回的值(如果删除了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函数。