以下代码应该创建频率分布的新(修改)版本(nltk.FreqDist)。两个变量应该是相同的长度。
在创建单个WebText实例时,它可以正常工作。但是当创建多个WebText实例时,新变量似乎被所有对象共享。
例如:
import nltk
from operator import itemgetter
class WebText:
freq_dist_weighted = {}
def __init__(self, text):
tokens = nltk.wordpunct_tokenize(text) #tokenize
word_count = len(tokens)
freq_dist = nltk.FreqDist(tokens)
for word,frequency in freq_dist.iteritems():
self.freq_dist_weighted[word] = frequency/word_count*frequency
print len(freq_dist), len(self.freq_dist_weighted)
text1 = WebText("this is a test")
text2 = WebText("this is another test")
text3 = WebText("a final sentence")
结果
4 4
4 5
3 7
哪个不对。由于我只是转置和修改值,因此每列中应该有相同的数字。 如果我在循环之前重置freq_dist_weighted,它可以正常工作:
import nltk
from operator import itemgetter
class WebText:
freq_dist_weighted = {}
def __init__(self, text):
tokens = nltk.wordpunct_tokenize(text) #tokenize
word_count = len(tokens)
freq_dist = nltk.FreqDist(tokens)
self.freq_dist_weighted = {}
for word,frequency in freq_dist.iteritems():
self.freq_dist_weighted[word] = frequency/word_count*frequency
print len(freq_dist), len(self.freq_dist_weighted)
text1 = WebText("this is a test")
text2 = WebText("this is another test")
text3 = WebText("a final sentence")
结果(正确):
4 4
4 4
3 3
这对我没有意义。
我不明白为什么我必须重置它,因为它在对象中是孤立的。我做错了吗?
答案 0 :(得分:9)
你的评论是完全错误的。类范围中的对象仅在创建类时初始化;如果你想为每个实例使用不同的对象,那么你需要将它移动到初始化器中。
class WebText:
def __init__(self, text):
self.freq_dist_weighted = {} #### RESET the dictionary HERE ####
...
答案 1 :(得分:6)
您的freq_dist_weighted
字典是类属性,而不是实例属性。因此,它在类的所有实例之间共享。 (self.freq_dist_weighted
仍然引用class属性;因为该名称没有特定于实例的属性,所以Python会回到查看该类。)
要使其成为实例属性,请在类的__init__()
方法中设置它。
def __init__(self, text):
self.freq_dist_weighted = {}
...
答案 2 :(得分:2)
class WebText:
freq_dist_weighted = {}
声明freq_dist_weighted
,以便在WebText
类型的所有对象之间共享;实质上,这就像C ++中的static
成员。
如果您希望每个WebText
对象拥有自己的freq_dist_weighted
成员(即您可以为一个实例更改它而不为另一个实例更改它),则需要在{{1}中定义它}:
__init__
答案 3 :(得分:2)
在创建单个WebText实例时,它可以正常工作。但是当创建多个WebText实例时,新变量似乎被所有对象共享。
嗯,是的;当然,当它们中的所有一个共享该值时,它将适用于单个实例。 ;)
该值是共享的,因为Python遵循一个非常简单的规则:您在class
块中定义的内容属于该类。即,它们不属于实例。要将某些内容附加到实例,您必须明确地执行此操作。这通常在__init__
中完成,但在正常情况下(即如果您没有使用__slots__
)可以随时完成。分配给对象的属性就像分配给列表的元素一样;没有真正的保护,因为我们都是成熟的成年人,并被认为是负责任的。
def __init__(self, text):
self.freq_dist_weighted = {}
# and proceed to modify it
可替换地:
def __init__(self, text):
freq_dist_weighted = {}
# prepare the dictionary contents first
self.freq_dist_weighted = freq_dist_weighted