2012-07-12 57 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