2012-04-10 51 views
0

我有一段非常討厭的代碼,我想重構,但是因爲它的總體不可讀。我該如何提高嵌套if和for語句的可讀性

for region in feed['config']['regions']: 
      if region['region'] == region_name: 
       for instance_type in region['instanceTypes']: 
        if instance_type['type'] == instance_type_name: 
         for instance_size in instance_type['sizes']: 
          if instance_size['size'] == instance_size_name: 
           for platform in instance_size['valueColumns']: 
            if platform['name'] == platform_name: 
             prices = platform['prices'] 
             assert prices.keys() == ['USD'] 
             return decimal.Decimal(prices['USD']) 
     assert False, "Failed to determine price for instance with region=%r, type=%r, size=%r, platform=%r" % \ 
       (region_name, instance_type_name, instance_size_name, platform_name) 

我已經爲每個循環或if語句使用函數,但這會給我一個函數負載。 有沒有解決方案?

+5

使用函數,所以y ou沒有超過2個嵌套for循環通常被認爲是很好的風格。 「一個函數的負載」是一件好事(tm),特別是如果你使用docstrings來記錄它們:-) – thebjorn 2012-04-10 07:37:22

+1

@thebjorn你的評論應該是一個答案 – 2012-04-10 07:42:42

回答

6
try: 
    region = [r for r in feed['config']['regions'] if region['region'] == region_name][0] 
    instance_type = [t for t in region['instanceTypes'] if i['type'] == instance_type_name][0] 
    # ... 
    return decimal.Decimal(prices['USD']) 
except IndexError: 
    raise Exception("Failed to determine price for instance with region=%r, type=%r, size=%r, platform=%r" % 
       (region_name, instance_type_name, instance_size_name, platform_name)) 

或一步:

def filter_by_key(key, value, objects): 
    return [o for o in objects if region[key] == value][0] 

try: 
    region = filter_by_key('region', region_name, feed['config']['regions']) 
    instance_type = filter_by_key('type', instace_type_name, region['instanceTypes']) 
    # ... 
    return decimal.Decimal(prices['USD']) 
except IndexError: 
    raise Exception("Failed to determine price for instance with region=%r, type=%r, size=%r, platform=%r" % 
       (region_name, instance_type_name, instance_size_name, platform_name)) 
2

如果你想保持它在一個循環中,您可以使用continue保存縮進:

for region in feed['config']['regions']: 
    if region['region'] != region_name: continue 
    for instance_type in region['instanceTypes']: 
     if instance_type['type'] != instance_type_name: continue 
     for instance_size in instance_type['sizes']: 
      if instance_size['size'] != instance_size_name: continue 
      for platform in instance_size['valueColumns']: 
       if platform['name'] != platform_name: continue 
       prices = platform['prices'] 
       assert prices.keys() == ['USD'] 
       return decimal.Decimal(prices['USD']) 
assert False, "Failed to determine price for instance with region=%r, type=%r, size=%r, platform=%r" % \ 
       (region_name, instance_type_name, instance_size_name, platform_name) 

或者與列表理解:

regions = (r for r in feed['config']['regions'] if r['region'] == region_name) 
instance_types = (i for i in r['instanceTypes'] for r in regions if i['type'] == instance_type_name) 
instance_sizes = (i for i in t['sizes'] for t in instance_types if i['size'] == instance_size_name) 
platforms = (p for p in s['valueColumns'] for s in instance_sizes if p['name'] == platform_name) 
for platform in platforms: 
    prices = platform['prices'] 
    assert prices.keys() == ['USD'] 
    return decimal.Decimal(prices['USD']) 
assert False, "Failed to determine price for instance with region=%r, type=%r, size=%r, platform=%r" % \ 
       (region_name, instance_type_name, instance_size_name, platform_name)