将类实例化为Iterable

时间:2012-07-12 20:46:53

标签: python tornado

我有一个我正在实例化的类,然后传入Tornado Web模板。这两个函数都返回一个列表,但是我错过了使Class本身成为可迭代对象的东西。我担心这是根本不正确的事情。我正在进行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__,但我不确定我究竟是如何理解的。

2 个答案:

答案 0 :(得分:2)

我相信你错过了班上__iter__的定义。

答案 1 :(得分:1)

我的建议如下:

  1. 创建一个类VM,用于存储有关单个VM的信息。其__init__应该获取您要存储的有关每个VM的信息,并将其设置为实例上的属性。如果您不需要任何实际代码来处理有关VM的数据,则可以使用collections.namedtuple,这将节省您编写__init__()方法的费用。

  2. getVMs()写为生成器,给定用户,密码和URL,生成一系列VM个实例。此结果可以按原样迭代,或者可以轻松转换为常规列表(如果需要)(只需将其传递给list())或用于创建将VM名称映射到OS的字典,反之亦然。

  3. e.g。 (此代码尚未经过测试):

    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对象提供名称和操作系统的XML,或整个VM的XML,但此示例实现仅将名称和操作系统作为字符串。

    (有更好的方法可以获取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))
    

    或者只打印每个VM的信息而不存储中间列表:

    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)}
    

    使用生成器模型使调用者最大程度地灵活。即使那个来电者是你,也会让你的生活更轻松。