<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 第四章 字典:當索引不好用時 > 來源:http://www.cnblogs.com/Marlowes/p/5320049.html > 作者:Marlowes 我們已經了解到,列表這種數據結構適合于將值組織到一個結構中,并且通過編號對其進行引用。在本章中,你將學到一種通過名字來引用值的數據結構。這種類型的數結構成為_映射_(mapping)。字典是Python中唯一內建的映射類型。字典中的值并沒有特殊的順序,但是都存儲在一個特定的鍵(Key)下。鍵可以是數字、字符串甚至是元組。 ## 4.1 字典的使用 _字典_這個名稱已經給出了有關這個數據結構功能的一些提示:一方面,對于普通的書來說,都是按照從頭到尾的順序進行閱讀。如果愿意,也可以快速翻到某一頁,這有點像Python的列表。另一方面,構造字典的目的,不管是現實中的字典還是在Python中的字典,都是為了可以通過輕松查找某個特定的詞語(鍵),從而找到它的定義(值)。 某些情況下,字典比列表更加適用,比如: √ 表示一個游戲棋盤的狀態,每個鍵都是由坐標值組成的元組; √ 存儲文件修改時間,用文件名作為鍵; √ 數字電話/地址簿。 假如有一個人名列表如下: ``` >>> names = ["Alice", "Beth", "Cecil", "Dee-Dee", "Earl"] ``` 如果要創建一個可以存儲這些人的電話號碼的小型數據庫,應該怎么做呢?一種方法是建立一個新的列表。假設只存儲四位的分機電話號碼,那么可以得到與下面相似的列表: ``` >>> numbers = ["2341", "9102", "3158", "0142", "5551"] ``` 建立了這些列表后,可以通過如下方式查找Cecil的電話號碼: ``` >>> numbers[names.index("Cecil")] '3158' ``` 這樣做雖然可行,但是并不實用。真正需要的效果應該類似以下面這樣: ``` >>> phonebook["Cecil"] '3158' ``` 你猜怎么著?如果`phonebook`是字典,就能像上面那樣操作了。 **整數還是數字字符串** 看到這里,讀者可能會有疑問:為什么用字符串而不用整數表示電話號碼呢?考慮一下Dee-Dee的電話號碼會怎么樣: ``` >>> 0142 98 ``` 這并不是我們想要的結果,是嗎?就像第一章曾經簡略地提到的那樣,八進制數字均以`0`開頭。不能像那樣表示十進制數字。 ``` >>> 0912 File "<stdin>", line 1 0912 ^ SyntaxError: invalid token ``` 教訓就是:電話號碼(以及其他可能以`0`開頭的數字)應該表示為數字字符串,而不是整數。 ## 4.2 創建和使用字典 字典可以通過下面的方式創建: ``` >>> phonebook = {"Alice": "2341", "Beth": "9102", "Cecil": "3258"} ``` 字典由多個_鍵_及與其對應的_值_構成的_鍵-值_對組成(我們也把鍵-值對稱為_項_)。在上例中,名字是鍵,電話號碼是值。每個鍵和它的值之間用冒號(`:`)隔開,項之間用逗號(`,`)隔開,而整個字典是由一對大括號括起來。空字典(不包括任何項)由兩個大括號組成,像這樣:`{}`。 _注:字典中的鍵是唯一的(其他類型的映射也是如此),而值并不唯一。_ ### 4.2.1 `dict`函數 可以用`dict`函數(`dict`函數根本不是真正的函數,它是個類型,就像`list`、`tuple`和`str`一樣),通過其他映射(比如其他字典)或者(鍵,值)對的序列建立字典。 ``` >>> items = [("name", "Gumby"), ("age", 42)] >>> d = dict(items) >>> d {'age': 42, 'name': 'Gumby'} >>> d["name"] 'Gumby' ``` `dict`函數也可以通過關鍵字參數來創建字典,如下例所示: ``` >>> d = dict(name="Gumby", age=42) >>> d {'age': 42, 'name': 'Gumby'} ``` 盡管這可能是`dict`函數最有用的功能,但是還能以映射作為`dict`函數的參數,以建立其項與映射相同的字典(如果不帶任何參數,則`dict`函數返回一個新的空字典,就像`list`、`tuple`以及`str`等函數一樣)。如果另一個映射也是字典(畢竟這是唯一內建的映射類型),也可以使用本章稍后講到的字典方法`copy`。 ### 4.2.2 基本字典操作 字典的基本行為在很多方面與序列(sequence)類似: √ `len(d)`返回`d`中項(鍵-值對)的數量; √ `d[k]`返回關聯到鍵`k`上的值; √ `d[k]=v`將值`v`關聯到鍵k上; √ `del d[k]`刪除鍵為`k`的項; √ `k in d`檢查`d`中是否有含有鍵為k的項。 盡管字典和列表有很多特性相同,但也有下面一些重要的區別。 √ 鍵類型:字典的鍵不一定為整型數據(但也可以是),鍵可以是任意的不可變類型,比如浮點型(實型)、字符串或者元組。 √ 自動添加:即使鍵起初在字典中并不存在,也可以為它賦值,這樣字典就會建立新的項。而(在不使用`append`方法或者其他類似操作的情況下)不能將值關聯到列表范圍之外的索引上。 √ 成員資格:表達式`k in d`(`d`為字典)查找的是_鍵_,而不是_值_。表達式`v in l`(`l`為列表)則用來查找_值_,而不是_索引_。這樣看起來好像有些不太一致,但是當習慣以后就會感覺非常自然了。畢竟,如果字典含有指定的鍵,查找相應的值也就很容易了。 _注:在字典中檢查鍵的成員資格比在列表中檢查值的成員資格更高效,數據結構的規模越大,兩者的效率差距越明顯。_ 第一點——鍵可以是任意不可變類型——是字典最強大的地方。第二點也很重要。看看下面的區別: ``` >>> x = [] # 列表 >>> x[42] = "Foobar" Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list assignment index out of range >>> x = {} # 字典 >>> x[42] = "Foobar" >>> x {42: 'Foobar'} ``` 首先,程序試圖將字符串`"Foobar"`關聯到一個空列表的42號位置上——這顯然是不可能的,因為這個位置根本不存在。為了將其變為可能,我必須用`[None]*43`或者其他方式初始化`x`,而不能僅使用`[]`。但是下一個例子工作得很好。我將`"Foobar"`關聯到空字典的鍵`42`上,沒問題!新的項已經添加到字典中,我達到目的了。 代碼清單4-1所示是電話本例子的代碼。 ``` 1 #!/usr/bin/env python 2 # coding=utf-8 3 4 # 一個簡單的數據庫 5 # 字典使用人名作為鍵。每個人用另一個字典來表示,其鍵"phone"和"addr"分別表示他們的電話號碼和地址。 6 7 people = { 8 9 "Alice": { 10 "phone": "2341", 11 "addr": "Foo drive 23" 12 }, 13 14 "Beth": { 15 "phone": "9102", 16 "addr": "Bar street 42" 17 }, 18 19 "Cecil": { 20 "phone": "3158", 21 "addr": "Baz avenue 90" 22 } 23 } 24 25 # 針對電話號碼和地址使用的描述性標簽,會在打印輸出的時候用到 26 labels = { 27 "phone": "phone number", 28 "addr": "address" 29 } 30 31 name = raw_input("Name: ") 32 33 # 查找電話號碼還是地址 34 request = raw_input("Phone number (p) or address (a)? ") 35 36 # 使用正確的鍵 37 if request == "p": 38 key = "phone" 39 if request == "a": 40 key = "addr" 41 42 # 如果名字是字典中的有效鍵才打印信息 43 if name in people: 44 print "%s's %s is %s." % (name, labels[key], people[name][key]) ``` Code_Listing 4-1 下面是程序的運行示例: ``` Name: Beth Phone number (p) or address (a)? a Beth's address is Bar street 42. ``` ### 4.2.3 字典的格式化字符串 在第三章,已經見過如何使用字符串格式化功能來格式化元組中所有的值。如果使用的是字典(只以字符串作為鍵的)而不是元組,會使字符串格式化更酷一些。在每個轉換說明符(conversion specifier)中的%字符后面,可以加上鍵(用圓括號括起來),后面再跟上其他說明元素。 ``` >>> phonebook {'Beth': '9102', 'Alice': '2341', 'Cecil': '3258'} >>> "Cecil's phone number is %(Cecil)s." % phonebook "Cecil's phone number is 3258." ``` 除了增加的字符串鍵之外,轉換說明符還是像以前一樣工作。當以這種方式使用字典的時候,只要所有給出的鍵都能在字典中找到,就可以使用任意數量的轉換說明符。這類字符串格式化在模板系統中非常有用(本例中使用HTML)。 ``` >>> template = """<html> ... <head><title>%(title)s</title></head> ... <body> ... <h1>%(title)s</h1> ... <p>%(text)s</p> ... </body>""" >>> data = {"title": "My Home Page", "text": "Welcome to my home page!"} >>> print template % data <html> <head><title>My Home Page</title></head> <body> <h1>My Home Page</h1> <p>Welcome to my home page!</p> </body> ``` _注:`string.Template`類(第三章提到過)對于這類應用也是非常有用的。_ ### 4.2.4 字典方法 就像其他內建類型一樣,字典也有方法。這些方法非常有用,但是可能不會像列表或者字符串方法那樣被頻繁地使用。讀者最好先簡單瀏覽一下本節,了解有哪些方法可用,然后在需要的時候再回過頭來查看特定方法的具體用法。 1\. `clear` `clear`方法清除字典中所有的項。這是個原地操作(類似于`list.sort`),所以無返回值(或者說返回`None`)。 ``` >>> d = {} >>> d["name"] = "Gumby" >>> d["age"] = 42 >>> d {'age': 42, 'name': 'Gumby'} >>> returned_value = d.clear() >>> d {} >>> print returned_value None ``` 為什么這個方法有用呢?考慮以下兩種情況。 ``` >>> x = {} # 第一種情況 >>> y = x >>> x["key"] = "value" >>> y {'key': 'value'} >>> x = {} >>> y {'key': 'value'} >>> x = {} # 第二種情況 >>> y = x >>> x["key"] = "value" >>> y {'key': 'value'} >>> x.clear() >>> y {} ``` 兩種情況中,`x`和`y`最初對應同一個字典。情況1中,我通過將`x`關聯到一個新的空字典來“清空”它,這對`y`一點影響也沒有,它還關聯到原先的字典。這可能是所需要的行為,但是如果真的想清空_原始_字典中的所有的元素,必須使用`clear`方法。正如在情況2中所看到的,`y`隨后也被清空了。 2\. copy `copy`方法返回一個具有相同鍵-值對的新字典(這個方法實現的是_淺復制_(shallow copy),因為值本身就是相同的,而不是副本)。 ``` >>> x = {"username": "admin", "machines": ["foo", "bar", "baz"]} >>> y = x.copy() >>> y["username"] = "mlh" >>> y["machines"].remove("bar") >>> y {'username': 'mlh', 'machines': ['foo', 'baz']} >>> x {'username': 'admin', 'machines': ['foo', 'baz']} ``` 可以看到,當在副本中替換值的時候,原始字典不受影響,但是,如果_修改_了某個值(原地修改,而不是替換),原始的字典也會改變,因為同樣的值也存儲在原字典中(就像上面例子中的`machines`列表一樣)。 避免這種問題的一種方法就是使用_深復制_(deep copy),復制其包含的所有值。可以使用`copy`模塊的`deepcopy`函數來完成操作: ``` >>> from copy import deepcopy >>> d = {} >>> d["names"] = ["Alfred", "Bertrand"] >>> c = d.copy() >>> dc = deepcopy(d) >>> d["names"].append("Clive") >>> c {'names': ['Alfred', 'Bertrand', 'Clive']} >>> dc {'names': ['Alfred', 'Bertrand']} ``` 3\. `fromkeys` `fromkeys`方法使用給定的鍵建立新的字典,每個鍵都對應一個默認的值`None`。 ``` >>> {}.fromkeys(["name", "age"]) {'age': None, 'name': None} ``` 剛才的例子中首先構造了一個空字典,然后調用它的`fromkeys`方法,建立另外一個字典——有些多余。此外,你還可以直接在`dict`上面調用該方法,前面講過,`dict`是所有字典的類型(關于類型和類的概念在第七章中會深入討論)。 ``` >>> dict.fromkeys(["name", "age"]) {'age': None, 'name': None} ``` 如果不想使用`None`作為默認值,也可以自己提供默認值。 ``` >>> dict.fromkeys(["name", "age"], "(unknown)") {'age': '(unknown)', 'name': '(unknown)'} ``` 4\. `get` `get`方法是個更寬松的訪問字典項的方法。一般來說,如果試圖訪問字典中不存在的項時會出錯: ``` >>> d = {} >>> print d["name"] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'name' ``` 而用`get`就不會: ``` >>> print d.get("name") None ``` 可以看到,當使用`get`訪問一個不存在的鍵時,沒有任何異常,而得到了`None`值。還可以自定義“默認”值,替換`None`: ``` >>> d.get("name", "N/A") 'N/A' ``` 如果鍵存在,`get`使用起來就像普通的字典查詢一樣: ``` >>> d["name"] = "Eric" >>> d.get("name") 'Eric' ``` 代碼清單4-2演示了一個代碼清單4-1程序的修改版本,它使用`get`方法訪問“數據庫”實體。 ``` 1 #!/usr/bin/env python 2 # coding=utf-8 3 4 # 一個簡單的數據庫 5 # 字典使用人名作為鍵。每個人用另一個字典來表示,其鍵"phone"和"addr"分別表示他們的電話號碼和地址。 6 7 people = { 8 9 "Alice": { 10 "phone": "2341", 11 "addr": "Foo drive 23" 12 }, 13 14 "Beth": { 15 "phone": "9102", 16 "addr": "Bar street 42" 17 }, 18 19 "Cecil": { 20 "phone": "3158", 21 "addr": "Baz avenue 90" 22 } 23 } 24 25 # 針對電話號碼和地址使用的描述性標簽,會在打印輸出的時候用到 26 labels = { 27 "phone": "phone number", 28 "addr": "address" 29 } 30 31 name = raw_input("Name: ") 32 33 # 查找電話號碼還是地址 34 request = raw_input("Phone number (p) or address (a)? ") 35 36 # 使用正確的鍵 37 key = request # 如果請求既不是"p"也不是"a" 38 39 if request == "p": 40 key = "phone" 41 if request == "a": 42 key = "addr" 43 44 # 使用get()提供默認值 45 person = people.get(name, {}) 46 label = labels.get(key, key) 47 result = person.get(key, "not available") 48 49 print "%s's %s is %s." % (name, label, result) ``` Code_Listing 4-2 以下是程序運行的輸出。注意`get`方法帶來的靈活性如何使得程序在用戶輸入我們并未準備的值時也能做出合理的反應。 ``` Name: Gumby Phone number (p) or address (a)? batting average Gumby's batting average is not available. ``` 5\. `has_key` `has_key`方法可以檢查字典中是否含有特定的鍵。表達式`d.has_key(k)`相當于表達式`k in d`。使用哪個方式很大程度上取決于個人的喜好。Python3.0中不包括這個函數。 下面是一個使用`has_key`方法的例子: ``` >>> d = {} >>> d.has_key("name") False >>> d["name"] = "Eric" >>> d.has_key("name") True ``` 6\. `items`和`iteritems` `items`方法將字典所有的項以列表方式返回,列表中的每一項都表示為(鍵, 值)對的形式。但是項在返回時并沒有遵循特定的次序。 ``` >>> d = {"title": "Python Web Site", "url": "http://www.python.org", "spam": "0"} >>> d.items() [('url', 'http://www.python.org'), ('spam', '0'), ('title', 'Python Web Site')] ``` `iteritems`方法的作用大致相同,但是會返回一個_迭代器_對象而不是列表: ``` >>> it = d.iteritems() >>> it <dictionary-itemiterator object at 0x00000000029BAEF8> >>> list(it) # Convert the iterator to a list [('url', 'http://www.python.org'), ('spam', '0'), ('title', 'Python Web Site')] ``` 在很多情況下使用`iteritems`會更加高效(尤其是想要迭代結果的情況下)。關于迭代器的更多信息,請參見第九章。 7\. `keys`和`iterkeys` `keys`方法將字典中的鍵以列表形式返回,而`iterkeys`則返回針對鍵的迭代器。 8\. `pop` `pop`方法用來獲得對應于給定鍵的值,然后將這個鍵-值對從字典中移除。 ``` >>> d = {"x": 1, "y": 2} >>> d.pop("x") 1 >>> d {'y': 2} ``` 9\. `popitem` `popitem`方法類似于`list.pop`,后者會彈出列表的最后一個元素。但不同的是,`popitem`彈出隨機的項,因為字典并沒有“最后的元素”或者其他有關順序的概念。若想一個接一個地移除并處理項,這個方法就非常有效了(因為不用首先獲取鍵的列表)。 ``` >>> d {'url': 'http://www.python.org', 'spam': '0', 'title': 'Python Web Site'} >>> d.popitem() ('url', 'http://www.python.org') >>> d {'spam': '0', 'title': 'Python Web Site'} ``` 盡管`popitem`和列表的`pop`方法很類似,但字典中沒有與`append`等價的方法。因為字典是無序的,類似于`append`的方法是沒有任何意義的。 10\. `setdefault` `setdefault`方法在某種程度上類似于`get`方法,能夠獲得與給定鍵相關聯的值,除此之外,`setdefault`還能在字典中不含有給定鍵的情況下設定相應的鍵值。 ``` >>> d = {} >>> d.setdefault("name", "N/A") 'N/A' >>> d {'name': 'N/A'} >>> d["name"] = "Gumby" >>> d.setdefault("name", "N/A") 'Gumby' >>> d {'name': 'Gumby'} ``` 可以看到,當鍵不存在的時候,`setdefault`返回默認值并且相應地更新字典。如果鍵存在,那么就返回與其對應的值,但不改變字典。默認值是可選的,這點和`get`一樣。如果不設定,會默認使用`None`。 ``` >>> d = {} >>> print d.setdefault("name") None >>> d {'name': None} ``` 11\. `update` `update`方法可以利用一個字典項更新另外一個字典: ``` >>> d = { ... "title": "Python Web Site", ... "url": "http://www.python.org", ... "changed": "Mar 14 22:09:15 MET 2008" ... } >>> x = {"title": "Python Language Website"} >>> d.update(x) >>> d {'url': 'http://www.python.org', 'changed': 'Mar 14 22:09:15 MET 2008', 'title': 'Python Language Website'} ``` 提供的字典中的項會被添加到舊的字典中,若有相同的鍵則會進行覆蓋。 `update`方法可以使用與調用`dict`函數(或者類型構造函數)同樣的方式進行調用,這點在本章前面已經討論。這就意味著`update`可以和映射、擁有(鍵、值)對的隊列(或者其他可迭代的對象)以及關鍵字參數一起調用。 12\. `values`和`itervalues` `values`方法以列表的形式返回字典中的值(`itervalues`返回值的迭代器)。與返回鍵的列表不同的是,返回值的列表中可以包含重復的元素: ``` >>> d = {} >>> d[1] = 1 >>> d[2] = 2 >>> d[3] = 3 >>> d[4] = 1 >>> d.values() [1, 2, 3, 1] ``` ## 4.3 小結 本章介紹了如下內容。 **映射**:映射可以使用任意不可變對象標識元素。最常用的類型是字符串和元組。Python唯一的內建映射類型是字典。 **利用字典格式化字符串**:可以通過在格式化說明符中包括名稱(鍵)來對字典應用字符串格式化操作。在當字符串格式化中使用元組時,還需要對元組中每一個元素都設定“格式化說明符”。在使用字典時,所用的說明符可以比在字典中用到的項少。 **字典的方法**:字典有很多方法,調用的方式和調用列表以及字符串方法的方式相同。 ### 4.3.1 本章的新函數 本章涉及的新函數如表4-1所示。 表4-1 本章的新函數 ``` dict(seq) 用(鍵、值)對(或者映射和關鍵字參數)建立字典。 ``` ### 4.3.2 接下來學什么 到現在為止,已經介紹了很多有關Python的基本數據類型的只是,并且講解了如何使用它們來建立表達式。那么請回想一下第一章的內容,計算機程序還有另外一個重要的組成因素——語句。下一章我們會對語句進行詳細的討論。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看