[英]Instantiate a Class as an Iterable
我有一個要實例化的類,然后傳遞給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__
,但是我不確定我是否確切了解它是如何工作的。
我相信您在課堂上缺少__iter__
的定義。
我的建議如下:
創建一個類VM
用於存儲有關單個虛擬機的信息。 它的__init__
應該獲取您要存儲的有關每個VM的信息,並將其設置為實例上的屬性。 如果不需要任何實際代碼來處理有關VM的數據,則可以使用collections.namedtuple
,這樣可以省去編寫__init__()
方法的__init__()
。
將getVMs()
作為生成器編寫,給定用戶,密碼和URL,生成一系列VM
實例。 此結果可以按原樣進行迭代,或者可以輕松轉換為常規列表(如果需要)(只需將其傳遞給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或整個VM的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))
或僅打印每個VM
的信息而不存儲中間列表:
for vm in getVMs(user, pass, url):
print vm.name, vm.os
或為VM實例構建名稱的字典(假定具有dict理解的Python的最新版本):
vmdict = {vm.name: vm for vm in getVMs(user, pass, url)}
使用生成器模型使其對於調用者具有最大的靈活性。 即使該呼叫者是您,也將使您的生活更輕松。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.