2012-07-12 16 views
0

我有一個類,我正在實例化,然後傳入一個Tornado Web模板。這兩個函數都返回一個列表,但我錯過了將類本身作爲一個可迭代對象的事情。我擔心這是我做錯事的根本原因。我正在進行REST API調用,解析返回的XML並將一些數據返回給webapp。下面的代碼:實例化一個類作爲可迭代的

的API調用:

class GetVMList: 

    def __init__(self): 
     user = 'contoso\\administrator' 
     password = "apassword" 
     url = "http://scspf:8090/SC2012/VMM/Microsoft.Management.Odata.svc/VirtualMachines?$filter=VMMServer%20eq%20'scvmm'" 

     passman = urllib2.HTTPPasswordMgrWithDefaultRealm() 
     passman.add_password(None, url, user, password) 
     # create the NTLM authentication handler 
     auth_NTLM = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passman) 

     # create and install the opener 
     opener = urllib2.build_opener(auth_NTLM) 
     urllib2.install_opener(opener) 

     # retrieve the result 
     self.response = urllib2.urlopen(url) 
     self.data = self.response.read() 

    def name(self): 
     dom = parseString(self.data) 
     raw_xml = dom.getElementsByTagName('d:Name') 
     clean_xml = [] 
     clean_data = [] 
     for i in raw_xml: 
      clean_xml.append(i.toxml()) 
     for i in clean_xml: 
      clean_data.append(i.replace('<d:Name>', '').replace('</d:Name>', '')) 
     return clean_data 

    def os(self): 
     dom = parseString(self.data) 
     raw_xml = dom.getElementsByTagName('d:OperatingSystem') 
     clean_xml = [] 
     clean_data = [] 
     for i in raw_xml: 
      clean_xml.append(i.toxml()) 
     for i in clean_xml: 
      clean_data.append(i.replace('<d:OperatingSystem>', '').replace('</d:OperatingSystem>', '')) 
     return clean_data 

的實例:

class ListHandler(tornado.web.RequestHandler): 
    def get(self): 
     self.render('temp/search.html', data='') 

    def post(self): 
     vm_list = GetVMList() 
     self.render('temp/search.html', data=vm_list) 

然後在模板中包含此:

{% for vm in data %} 
<li>{{ vm.name }} running {{ vm.os }}</li> 
{% end %} 

的錯誤是:TypeError: iteration over non-sequence。我想我需要在我的課程中使用__iter__,但我不確定我是否明白它的工作原理。

+1

我沒有看到'__iter __()'方法,所以'GetVMList'類的實例當然不是可迭代的。另外,你可能不應該命名類GetVMList(),而應該命名爲'VMList()'...類是名詞,而不是動詞。最後,你可能真的想要一個迭代器/生成器,而不是一個類。最重要的是,一個* list *的虛擬機不會有'name'或'os',這些是各個虛擬機的屬性,但是你沒有提供任何指定你想要哪個虛擬機名稱或操作系統的方法的。你非常需要重新考慮你的設計。 – kindall 2012-07-12 20:49:48

+0

應該返回什麼?例如'GetVMList()中的x:print x'應該打印什麼? – mgilson 2012-07-12 20:51:17

+0

@ kindall非常感謝,這正是這種建議。這不是我所知道的很多;你的建議是非常有用的。我想'__iter__'是我需要的,但不確定如何實現它。 – Danielscottt 2012-07-12 23:39:33

回答

1

我的建議是以下幾點:

  1. 用於存儲有關單個虛擬機的信息創建一個類​​。它的__init__應該獲取你想要存儲的有關每個虛擬機的信息,並將其設置爲實例上的屬性。如果您不需要任何實際的代碼來處理有關虛擬機的數據,則可以使用collections.namedtuple,這將使您無需編寫__init__()方法。

  2. 編寫getVMs()作爲一個生成器,給定用戶,密碼和URL,生成一個​​實例序列。這個結果可以按原樣迭代,或者如果需要的話可以很容易地轉換爲常規列表(只需將它傳遞給list())或用於創建將VM名稱映射到OS或反之亦然的字典。

例如, (此代碼沒有經過測試):

class VM(object): 
    def __init__(self, name, os): 
     self.name = name 
     self.os = os 

def getVMs(user, password, URL): 
    passman = urllib2.HTTPPasswordMgrWithDefaultRealm() 
    passman.add_password(None, url, user, password) 
    auth_NTLM = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passman) 
    urllib2.install_opener(urllib2.build_opener(auth_NTLM)) 
    dom = parseString(urllib2.urlopen(url).read()) 
    for vmnode in dom.getElementsByTagName('d:VM') # the tag representing a VM 
     name = vmnode.getElementsByTagName('d:Name')[0] # get name of current VM 
     name = name.replace('<d:Name>', '').replace('</d:Name>', '') 
     os = vmnode.getElementsByTagName('d:OperatingSystem')[0] # same for OS 
     os = os.replace('<d:OperatingSystem>', '').replace('</d:OperatingSystem>', '')) 
     yield VM(name, os) 

...你也可以給你的VM對象的名稱和OS,或XML整個虛擬機的XML,但是本示例實現只做了名稱和OS作爲字符串。

(有更好的方法來獲得一個DOM節點的內容,而不訴諸更換空白字符串的XML標籤,但我沒有時間去做這些事情現在)

調用它:

user = r"contoso\administrator" 
pass = "apassword" 
url = ("http://scspf:8090/SC2012/VMM/Microsoft.Management.Odata.svc" 
     "/VirtualMachines?$filter=VMMServer%20eq%20'scvmm'") 

vmlist = list(getVMs(user, pass, url)) 

或只打印每個​​的信息不存儲中間列表:

for vm in getVMs(user, pass, url): 
    print vm.name, vm.os 

,或建立名稱以VM實例字典(假設最近版本的Python有dict解析):

vmdict = {vm.name: vm for vm in getVMs(user, pass, url)} 

使用生成器模型使得它對調用者來說是最靈活的。即使這位來電者是你,也會讓你的生活更輕鬆。

+0

'yield'是_definitely_我需要教的概念。這很有效,再次感謝。 – Danielscottt 2012-07-13 16:54:13

+0

是的,對於很多問題,「yield」是一個令人驚訝的簡單解決方案。 – kindall 2012-07-13 18:10:07