2013-02-03 43 views
0

我今天遇到了一個奇怪的問題意外的行爲,這裏是一些示例代碼與defaultdict

from collections import defaultdict 

class Counter: 
    hits = 0 
    visitors = set() 

    def addHit(self, ip): 
     self.hits += 1 
     self.visitors.add(ip) 

d = defaultdict(Counter) 
d['a'].addHit('1.1.1') 
d['a'].addHit('2.2.2') 
d['b'].addHit('3.3.3') 

print d['a'].hits, d['a'].visitors 
print d['b'].hits, d['b'].visitors 

預期結果:

2 set(['1.1.1', '2.2.2']) 
1 set(['3.3.3']) 

實際結果:

2 set(['1.1.1', '3.3.3', '2.2.2']) 
1 set(['1.1.1', '3.3.3', '2.2.2']) 

爲什麼是訪問者在我認爲應該是Counter類的單獨實例之間設置共享數據。不應該每個輸入指向特定的實例?

是什麼使這個更難理解的是,熱門計數器似乎工作正常,並保持獨立。

任何人都可以幫助我瞭解這裏發生了什麼或如何解決它?

+0

措辭不同,但相同的問題http://stackoverflow.com/questions/14667465/multiple-instances-of-a-python-object-are-acting-like-the-same-實例 – tacaswell

回答

4

我懷疑你的訪問者是一個類變量而不是實例變量。

與defaultdicts行爲無關。

嘗試:

class Counter: 
    def __init__(self): 
     self.hits = 0 
     self.visitors = set() 

    def addHit(self, ip): 
     self.hits += 1 
     self.visitors.add(ip) 

編輯: 無關,與你的問題,但只是一些想法如何擴大你的計數器:

#! /usr/bin/python3.2 

class Counter: 
    def __init__(self): 
     self.__hits = 0 
     self.__visitors = {} 

    def addHit(self, ip): 
     self.__hits += 1 
     if ip not in self.__visitors: 
      self.__visitors [ip] = 0 
     self.__visitors [ip] += 1 

    @property 
    def hits (self): 
     return self.__hits 

    @property 
    def uniqueHits (self): 
     return len (self.__visitors) 

    @property 
    def ips (self): 
     return (ip for ip in self.__visitors) 

    def __getitem__ (self, ip): 
     return 0 if ip not in self.__visitors else self.__visitors [ip] 

c = Counter() 

c.addHit ('1.1.1.1') 
c.addHit ('1.1.1.1') 
c.addHit ('1.1.1.1') 
c.addHit ('1.1.1.1') 
c.addHit ('1.1.1.2') 
c.addHit ('1.1.1.2') 
c.addHit ('1.1.1.3') 

print (c.hits) 
print (c.uniqueHits) 
for ip in c.ips: 
    print (ip, c [ip]) 
+0

感謝你的解決方案。我不確定我需要計算每個獨特訪問者的點擊次數,但感謝擴展了一點 –

2

這是完全一樣的問題,因爲Multiple Instances of a Python Object are acting like the same instance

您正在使用類級變量。將其更改爲

class Counter: 
    def __init__(self): 
     self.hits = 0 
     self.visitors = set() 

    def addHit(self, ip): 
     self.hits += 1 
     self.visitors.add(ip) 
+1

哈哈。一個想法,兩個愚蠢。你和我發佈了相同的代碼。 – Hyperboreus

+0

@Hyperboreus那麼,有一點宣言說,應該只有一種方式在Python中做事情;) – tacaswell

+0

而對於那些想知道他們如何閱讀「pythonist宣言」的人來說,只需'import this' ...並且然後,爲了一點額外的樂趣,閱讀來源:) – mgilson