2015-01-04 262 views
2

作爲內部項目的一部分,我必須解析dns區域文件記錄。該文件看起來大致如此。Python從配置創建詞典字典

$ORIGIN 0001.test.domain.com. 
    test-qa  CNAME test-qa.0001.test.domain.com. 
    $ORIGIN test-qa.domain.com. 
    unit-test01  A 192.168.0.2 
    $TTL 60 ; 1 minute 
    integration-test A 192.168.0.102 
    $ORIGIN dev.domain.com. 
    web  A  192.168.10.10 
    $TTL 300; 5 minutes 
    api  A 192.168.10.13 

默認TTL是3600,也就是說,對於上述數據,

test-qa  CNAME test-qa.0001.test.domain.com. 

有一個3600的TTL,因爲它沒有任何地方提到$ TTL。然而,

unit-test01  A 192.168.0.2 

有一個3600的TTL和

integration-test A 192.168.0.102 

有60秒一個TTL。

我想從上面的這些數據中創建一個數據結構,我猜字典將是遍歷這些數據的最佳方式。

我所做的:

origin = re.compile("^\$ORIGIN.*") 
ttl = re.compile("^$TTL.*") 
default_ttl = "$TTL 3600" 
data_dict = {} 
primary_key = None 
value = None 
for line in data_zones: 
    if origin.search(line): 
      line = line.replace("$ORIGIN ", "") 
      primary_key = line 
    elif ttl.search(line): 
      default_ttl = line 
    else: 
      value = line 
    data_dict[primary_key] = [default_ttl] 
    data_dict[primary_key][default_ttl] = value 

我想將它轉換成一個字典,但我得到的錯誤

TypeError: list indices must be integers, not str 

我的樣本數據結構需要看起來像

0001.test.domain.com.: #This would be the first level Key 
    ttl:3600: #This would be the second level key 
     test-qa  CNAME test-qa.0001.test.domain.com. #Value 

test-qa.domain.com.: #This would be the first level Key 
    ttl:3600: #This would be the second level key 
     unit-test01  A 192.168.0.2 #value 
    ttl:60: #This would be the second level key 
     integration-test  A 192.168.0.102 #value 

我在這裏做錯了什麼?

回答

2

在我們查看問題的細節之前,可以在代碼中清除一些可以使錯誤更容易找到的東西。遵循代碼質量準則使代碼更易於維護和理解,特別是 - 變量名稱應始終是描述性的,並告訴讀者變量將代表什麼。一個錯誤的變量名不會告訴讀者它包含什麼,而一個可怕的變量名會告訴讀者變量包含它沒有的東西。

這裏我們有一個名爲default_ttl的變量。偶然的讀者可能會假設這個變量總是包含默認的ttl,但是在上面的代碼示例中,只要源數據中指定了ttl,變量就會被覆蓋。

default_ttl = line 

這可能是一個更加清晰指定的代碼的頂部缺省TTL,然後用這個值分配給一個變量叫,說:current_ttl,每當遇到新的原點。

所以在文件的頂部,我們將有:

DEFAULT_TTL = '$TTL 3600' 

而每遇到一個新的起源時間,目前的TTL將被重置爲默認值。

if origin.search(line): 
      line = line.replace("$ORIGIN ", "") 
      current_ttl = DEFAULT_TTL 

當在源數據中遇到特定TTL,適當的值然後被分配給當前TTL:

elif ttl.search(line): 
     current_ttl = line 

一旦這種變化是由,代碼的底部兩條線將成爲:

data_dict[primary_key] = [current_ttl] 
data_dict[primary_key][current_ttl] = value 

錯誤的原因是要創建恰好包含一個條目列表 - 在current_ttl,並創建包含該data_dict詞典中的條目名單。

在下一行中,您將列表從字典中取出,並嘗試使用索引current_ttl訪問它。 current_ttl包含一個字符串,並且只能使用整數訪問列表。翻譯給你一個錯誤信息,簡單地總結一下!

不進行重大修改你的代碼,最快捷的清理是使用defaultdict爲頂級data_dict:

from collections import defaultdict 
data_dict = defaultdict(dict) 

所以,現在,每當我們試圖指在data_dict確實不關鍵存在時,將由defaultdict對象爲我們創建一個新的空字典,並將其插入到我們嘗試訪問的該密鑰的data_dict中。

data_dict[primary_key] = [default_ttl] 

現在是多餘的和不必要的,它可從代碼完全移除,留下:

from collections import defaultdict 
origin = re.compile("^\$ORIGIN.*") 
ttl = re.compile("^$TTL.*") 
DEFAULT_TTL = "$TTL 3600" 
data_dict = defaultdict(dict) 
primary_key = None 
value = None 
for line in data_zones.split('\n'): #Split by line not character 
    if origin.search(line): 
       line = line.replace("$ORIGIN ", "") 
       current_ttl = DEFAULT_TTL 
       primary_key = line 
    elif ttl.search(line): 
      current_ttl = line 
    else: 
      value = line 
    data_dict[primary_key][current_ttl] = value 
1

誤差的線是

data_dict[primary_key][default_ttl] = value 

由於data_dict[primary_key]是一個列表,而不是一個字典對象。你可以通過這樣做來解決這個問題

data_dict[primary_key] = {default_ttl: value}