我有一个我正在实例化的类,然后传入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__
,但我不确定我究竟是如何理解的。
答案 0 :(得分:2)
我相信你错过了班上__iter__
的定义。
答案 1 :(得分:1)
我的建议如下:
创建一个类VM
,用于存储有关单个VM的信息。其__init__
应该获取您要存储的有关每个VM的信息,并将其设置为实例上的属性。如果您不需要任何实际代码来处理有关VM的数据,则可以使用collections.namedtuple
,这将节省您编写__init__()
方法的费用。
将getVMs()
写为生成器,给定用户,密码和URL,生成一系列VM
个实例。此结果可以按原样迭代,或者可以轻松转换为常规列表(如果需要)(只需将其传递给list()
)或用于创建将VM名称映射到OS的字典,反之亦然。
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)}
使用生成器模型使调用者最大程度地灵活。即使那个来电者是你,也会让你的生活更轻松。