2012-04-03 20 views
0

在doctest和shell中使用相同的代碼會產生不同的輸出。
我有一個函數叫做a(),它運行幾個測試。
在doctest(test())中使用了相同的測試。
用()我得到OBJECT-BLANKLINE-OBJECT,而test()給我一個錯誤,只顯示第一個對象。
這是doctest模塊中的缺陷嗎?Doctest的輸出與shell的輸出不同

這裏的整個文件既具有()和test()在頂部:

''' 
>>> u1 = User("[email protected]", "simples") 
>>> u2 = User("[email protected]", "complicada") 
>>> u2.askFriend(u1) 
>>> u1.recvRequest(u2) 
>>> u1.confirmFriend(u2) 
>>> p1 = Post(u1, "O ultimo post", "http://www.wikipedia.org") 
>>> p2 = Post(u2, "A ultima resposta", "http://www.google.com") 
>>> c = Comments() 
>>> c.add(p1) 
>>> c.add(p2) 
>>> f1 = c.search(user="[email protected]") 
>>> print(f1) 
A ultima resposta 
http://www.google.com 
0 Gosto, 0 Nao gosto 
>>> f2 = c.search(likes=1) 
>>> print(f2) 
<BLANKLINE> 
>>> f3 = c.search(text='post') 
>>> print(f3) 
O ultimo post 
http://www.wikipedia.org 
0 Gosto, 0 Nao gosto 
<BLANKLINE> 
A ultima resposta 
http://www.google.com 
0 Gosto, 0 Nao gosto 
''' 

def test(): 
    import doctest 
    doctest.testmod() 

def a(): 
    u1 = User("[email protected]", "simples") 
    u2 = User("[email protected]", "complicada") 
    u2.askFriend(u1) 
    u1.recvRequest(u2) 
    u1.confirmFriend(u2) 
    p1 = Post(u1, "O ultimo post", "http://www.wikipedia.org") 
    p2 = Post(u2, "A ultima resposta", "http://www.google.com") 
    c = Comments() 
    c.add(p1) 
    c.add(p2) 
    f3 = c.search(text="post") 
    print(f3) 

import string 

class User: 

    def __init__(self,email,passwd): 
     self.email = email 
     self.passwd = passwd 
     self.name = None 
     self.year = None 
     self.active = True 
     self.recv = [] 
     self.conf = [] 
     self.setPassword(self.passwd) 

    def __str__(self): 
     if self.name == None and self.active == True: 
      return str(self.email) + ':' + 'ativa' 

     elif self.name != None and self.active == True: 
      return str(self.name) + ':' + str(self.email) + ':' + 'ativa' 

     elif self.name != None and self.active == False: 
      return str(self.name) + ':' + str(self.email) + ':' + 'inativa' 

     else: 
      return str(self.email) + ':' + 'inativa' 

    def getEmail(self): 
     return self.email 

    def setPassword(self,passwd): 
     abc = string.ascii_lowercase 
     cifra = abc[3:] + abc[:3] 
     dec = list(passwd) 
     passwdCif = "" 
     for i in dec: 
      cif = cifra[abc.find(i)] 
      passwdCif += cif 
     self.passwd = passwdCif 

    def getPassword(self): 
     return self.passwd 

    def setName(self,name): 
     self.name = name 

    def getName(self): 
     return self.name 

    def setBirth(self,year,month,day): 
     self.year = year 
     self.month = month 
     self.day = day 

    def getBirth(self): 
     if self.year == None: 
      return None 
     else: 
      return '(' + str(self.year) + ', ' + str(self.month) + ', ' + str(self.day) + ')' 

    def isActive(self): 
     if self.active == True: 
      return True 
     else: 
      return False 

    def setActive(self): 
     self.active = True 

    def setInactive(self): 
     self.active = False 

    def askFriend(self,u): 
     self.conf.append(u) 

    def recvRequest(self,u): 
     self.recv.append(u) 

    def confirmFriend(self,u): 
     if len(self.recv) == 0: 
      return None 
     else: 
      for i in self.recv: 
       if i == u: 
        self.recv.remove(i) 
        self.conf.append(i) 
       else: 
        return None 


    def isFriend(self,u): 
     if u in self.conf: 
      return True 
     elif self == u: 
      return True 
     else: 
      return False 

    def showPending(self): 
     if len(self.recv) == 0: 
      return None 
     else: 
      for i in self.recv: 
       print i 

    def showFriends(self): 
     if len(self.conf) == 0: 
      return None 
     else: 
      for i in self.conf: 
       print i 

class Post(): 
    def __init__(self,u,text='',link=None): 
     self.u = u 
     self.text = text 
     self.link = link 
     self.seg = None 
     self.ant = None 
     self.likeList = [] 
     self.dislikeList = [] 

    def __str__(self): 
     if self.link == None: 
      return str(self.text) + '\n' + str(len(self.likeList)) + ' Gosto, ' + str(len(self.dislikeList)) + ' Nao gosto' 
     else: 
      return str(self.text) + '\n' + str(self.link) + '\n' + str(len(self.likeList)) + ' Gosto, ' + str(len(self.dislikeList)) + ' Nao gosto' 

    def updateText(self,text): 
     self.text = text 

    def updateLink(self,link): 
     self.link = link 

    def like(self,u): 
     if (u in self.u.conf) or (u == self.u): 
      if u in self.dislikeList: 
       self.dislikeList.remove(u) 
       self.likeList.append(u) 
      elif u in self.likeList: 
       return None 
      else: 
       self.likeList.append(u) 
     else: 
      return None 

    def dislike(self,u): 
     if (u in self.u.conf) or (u == self.u): 
      if u in self.likeList: 
       self.likeList.remove(u) 
       self.dislikeList.append(u) 
      elif u in self.dislikeList: 
       return None 
      else: 
       self.dislikeList.append(u) 
     else: 
      return None 

class Comments(): 
    def __init__(self, u=None, text='', link=None): 
     self.u = u 
     self.text = text 
     self.link = link 
     self.topo = None 
     self.fim = None 

    def __str__(self): 
     actual = self.topo 
     s = '' 
     if actual == None: 
      return '' 
     while actual != None: 
      if actual.seg == None: 
       s += str(actual) 
       actual = actual.seg 
      elif actual.seg != None: 
       s += str(actual) + '\n' + '\n' 
       actual = actual.seg 
     return s 

    def add(self,comment): 
     if self.topo == None: 
      comment.ant = None 
      comment.seg = None 
      self.topo = comment 
      self.fim = comment 
     else: 
      comment.ant = None 
      comment.seg = self.topo 
      self.topo.ant = comment 
      self.topo = comment 

    def remove(self,comment): 
     actual = self.topo 
     if (self.topo == self.fim) and (self.topo == comment): 
      self.topo = None 
      self.fim = None 
      actual = None 
     while actual!=None: 
      if actual == comment: 
       if actual.ant == None: 
        self.topo = actual.seg 
        actual.seg.ant = None 
       elif actual.seg == None: 
        self.fim = actual.ant 
        actual.ant.seg = None 
       else: 
        actual.seg.ant = actual.ant 
        actual.ant.seg = actual.seg 
       break 
      else: 
       actual = actual.seg 

    def countLike(self): 
     count = 0 
     actual = self.topo 
     while actual != None: 
      if len(actual.likeList) >= 1: 
       count += 1 
       actual = actual.seg 
      else: 
       actual = actual.seg 
     return count 

    def showRecentComments(self,n): 
     count = 1 
     actual = self.topo 
     sC = '' 
     if actual == None: 
      return None 
     while actual != None: 
      if count < n: 
       if actual.seg == None: 
        sC += str(actual) 
        count += 1 
        actual = actual.seg 
       else: 
        sC += str(actual) + '\n' + '\n' 
        count += 1 
        actual = actual.seg 
      elif count == n: 
       sC += str(actual) 
       count += 1 
       actual = actual.seg 
      elif count > n: 
       break 
     print sC 

    def search(self, user=None, likes=None, dislikes=None, text=None): 
     result = [] 
     actual = self.topo 
     cR = Comments() 
     if actual == None: 
      return None 

     while actual != None: 
      if user != None: 
       if actual.u.email != user: 
        actual = actual.seg 
       elif actual.u.email == user: 
        result.append(actual) 
        actual = actual.seg 
      elif user == None: 
       break 
     actual = self.topo 

     while actual != None: 
      if likes != None: 
       if likes > len(actual.likeList): 
        actual = actual.seg 
       elif likes <= len(actual.likeList): 
        if actual in result: 
         actual = actual.seg 
        else: 
         result.append(actual) 
         actual = actual.seg 
      elif likes == None: 
       break 
     actual = self.topo 

     while actual != None: 
      if dislikes != None: 
       if dislikes > len(actual.dislikeList): 
        actual = actual.seg 
       elif dislikes <= len(actual.dislikeList): 
        if actual in result: 
         actual = actual.seg 
        else: 
         result.append(actual) 
         actual = actual.seg 
      elif dislikes == None: 
       break 
     actual = self.topo 

     while actual != None: 
      if text != None: 
       if text not in actual.text: 
        actual = actual.seg 
       elif text in actual.text: 
        if actual in result: 
         actual = actual.seg 
        else: 
         result.append(actual) 
         actual = actual.seg 
      elif text == None: 
       break 
     if len(result) != 0: 
      for i in result: 
       cR.add(i) 
     return cR 

這裏是我開始使用同時輸出一個()和test():

>>> a() 
O ultimo post 
http://www.wikipedia.org 
0 Gosto, 0 Nao gosto 

A ultima resposta 
http://www.google.com 
0 Gosto, 0 Nao gosto 
>>> test() 
********************************************************************** 
File "__main__", line 22, in __main__ 
Failed example: 
    print(f3) 
Expected: 
    O ultimo post 
    http://www.wikipedia.org 
    0 Gosto, 0 Nao gosto 
    <BLANKLINE> 
    A ultima resposta 
    http://www.google.com 
    0 Gosto, 0 Nao gosto 
Got: 
    A ultima resposta 
    http://www.google.com 
    0 Gosto, 0 Nao gosto 
********************************************************************** 
1 items had failures: 
    1 of 16 in __main__ 
***Test Failed*** 1 failures. 
>>> 

我也想爲我以前嚴重質疑的問題道歉。
希望這一個會幫助我和其他人。

+0

您應該將代碼縮小到最短的版本,但仍然會產生相同的行爲。這樣你可能會自己發現問題。 – marue 2012-04-03 23:34:51

+0

你應該真的看看這個:http://stackoverflow.com/questions/how-to-ask雖然你提供了很多代碼,但你在黑暗中使用它的情況很少:至少顯示您的測試代碼。 – marue 2012-04-03 23:46:53

+0

改寫了問題。 – 2012-04-04 11:25:21

回答

2

還有就是你的文檔測試和你的函數之間有一個明顯的區別:當你的功能做到這一點:

# previous code 
c.add(p2) 
f3 = c.search(text="post") 
print(f3) 

您的文檔測試做到這一點:

# previous code 
c.add(p2) 
f1 = c.search(user="[email protected]") 
print(f1) 
f2 = c.search(likes=1) 
print(f2) 
f3 = c.search(text='post') 
print(f3) 

我不知道到底發生了什麼有,但可能你應該寫你的函數來做同樣的事情。如果結果仍然不同,則doctest有問題,否則使用您的代碼。

編輯:

現在我開始明白爲什麼你的麻煩,這是deeeeeeep麻煩。它從這條線開始在您的搜索功能之上:

actual = self.topo 

我想你不知道Python分配屬性的方式。後來在您的代碼更改實際的,然後再指定self.topo實際:

actual.seg = "somevalue" # sorry, i can't remember what you did" 
actual = self.topo 

也就是說第二行是完全沒有意義的,因爲實際已經是self.topo!這不是self.topo的價值,而是self.topo。

而是寫

actual.seg = "somevalue" 

,你可以只寫

self.topo.seg = "somevalue" 

兩條線都做同樣的。所以,當你認爲你正在改變一些獨立的財產actual你真的改變self.topo所有的時間。這意味着actual在函數的每個開始處都不相等,但始終具有最後一次運行c.search時的值。

我剛剛看到您在其他一些函數中也這樣做了,這意味着您每次調用這樣的函數時都會改變評論實例c的狀態。當然,這對每個測試都會產生不同的輸出結果。

爲了使這更容易理解,這裏是一個列表的示例:

>>> a_list = ['one','two','three'] 
>>> b_list = a_list 
>>> b_list.pop() 
'three' 
>>> a_list 
['one', 'two'] 

正如你看到的:Allthoug我並從彈出的b_list元素,它是從消失的a_list爲好。這是因爲b_list = a_list陳述的字面意思是b_list現在與a_list相同。

希望這會有所幫助。

+0

我怎樣才能「清理」參數而不會丟失其中的帖子? 我在搜索功能中嘗試了一些東西,但我現在不是真的如何。 – 2012-04-04 16:57:22

+0

哎呀,對不起。更正了我的答案,解釋是錯誤的。也許我有時間再看看它。 – marue 2012-04-04 17:43:15

+0

解釋實際上是錯誤的,就像你說的。 我做了一些額外的測試,文字部分不能正常工作 – 2012-04-04 20:00:02