Python 字典

lua-users home
wiki

[!] VersionNotice:以下程式碼用於較舊的 Lua 版本,Lua 4。Lua 5 中不再使用特定功能,例如標籤方法 (settagmethod),它們已改用元方法。

簡介

Lua 的表格類型是一個多功能容器,它介於 Pythons 清單和字典類型之間。以下清單模擬 Python 字典。請參閱 Python 對應類型文件的說明,了解此處實作的內容 [1]。請參閱 PythonListsClassesAndMethods,深入了解實作方式。此腳本是為 Lua 版本 4.0 編寫的。

此程式碼是利用 Lua 模擬 Python 功能的練習。它拋出一些 Lua 中的問題,這些問題似乎已在 Lua 4.1 中解決。對此實作的說明:

抱歉,這無法運作。請嘗試
foo = Dict:new { len="vcbvcb" }
print(foo:len())
冒號運算子存取 foo,而非 Dict。您會將遺失的元素 (方法) 重新導向至 Dict,但如果名稱已存在於 foo 中,就會採用該名稱。請閱讀 [2],取得可能的 (已實作且可運作的) 解決方案。-- ET

因此,解決方案是新增
settagmethod(tag(Dict), "gettable", 
          function(t,k)
            if rawget(Dict,k) then
              return rawget(Dict,k)
            else
              return rawget(t,k)
            end
          end )
它將停止使用者資料和 dict 實作之間的衝突。--NDT

抱歉,它無法停止衝突。您只是交換了優先順序;衝突仍然存在。現在 foo:len() 會提供 1,但 foo.len 會提供函數,而非儲存的值 "vcbvcb"。順帶一提,PythonLists 只能運作,因為使用者索引 (一律為數字) 和方法 (一律為字串) 之間沒有衝突。-- ET

程式碼

-- Emulation of Python dictionaries
-- Nick Trout -- thanks to lhf & ET
-- See http://www.python.org/doc/current/lib/typesmapping.html
-- $Header: /Tools/build/pydict.lua 3     11/09/01 14:20 Nick $

Dict = settag({},newtag())

-- handle access to our dictionary table type
function Dict._gettable(t,k)
  -- print("gt",t,k)
  -- See if the key we are looking for is a method in Dict.
  -- Note the user may have used a key which has the same name as
  -- one of our functions, but methods take precidence . eg.
  -- foo = Dict:new { len="vcbvcb" }  print(foo:len())
  local v = rawget(Dict,k)
  if v then
    return v
  else
    -- In Python, if we dont find a key in a dictionary we raise a Key error.
    v = rawget(t,k)
    assert(v,"Key error")
    return v
  end
end

settagmethod(tag(Dict), "gettable", Dict._gettable)

-- Create a new dictionary.
-- eg. dict = Dict:new()  or  dict = Dict:new{ a=1,b=2 }
function Dict:new(t)
  if not t then t={} end
  settag(t,tag(Dict))
  return t
end

-- len(a) the number of items in a
function Dict:len()
  -- Note: Lua returns the number of indexed objects, not mapped objects with getn
  local cnt=0
  for k,v in self do cnt=cnt+1 end
  return cnt
end

-- Python: a[k] the item of a with key k (1)
-- Lua: dict[k]

-- Python: a[k] = v set a[k] to v
-- Lua: dict[k] = v

-- Python: del a[k] remove a[k] from a (1)
-- Lua: dict:del(k)
function Dict:del(k)
  self[k] = nil
end

-- Python: a.clear() remove all items from a
-- Lua: dict:clear()
function Dict:clear()
  -- cannot do self = {} as self passed by value
  -- we cannot change a table inside a for loop
  -- eg.  for k,v in self do self[k]=nil end
  -- Must collect keys and delete them thus:
  local t={}
  for k,v in self do t[k]=1 end
  for k,v in t do self[k]=nil end
end

-- Python: a.copy() a (shallow) copy of a
-- Lua: dictcopy = dict:copy()
function Dict:copy()
  local d = Dict:new()
  for k,v in self do d[k] = v end
  return d
end

-- Python:  k in a 1 if a has a key k, else 0
-- k not in a 0 if a has a key k, else 1
-- a.has_key(k) Equivalent to k in a
function Dict:has_key(k)
  return self[k]  -- return value for true, or nil for false
end

-- Python: a.items() a copy of a's list of (key, value) pairs
function Dict:items()
  local items={}
  for k,v in self do tinsert(items,{k,v}) end
  return items
end

-- Python: a.keys() a copy of a's list of keys
function Dict:keys()
  local keys={}
  for k,v in self do tinsert(keys,k) end
  return keys
end

-- Python: a.update(b) for k in b.keys(): a[k] = b[k]
-- Add b to a
function Dict:update(b)
  assert(type(b)=="table")
  for k,v in b do self[k] = v end
end

-- Python: a.values() a copy of a's list of values
function Dict:values()
  local vals={}
  for k,v in self do tinsert(vals,v) end
  return vals
end

-- Python: a.get(k[, x]) a[k] if k in a, else x
-- Return the value associated with key k or x is key not found
function Dict:get(k,x)
  -- use rawget to avoid invoking "index" tag method if k not found
  return rawget(self,k) or x
end

-- Python: a.setdefault(k[, x]) a[k] if k in a, else x (also setting it)
-- Set value for k to x if k not found, also return value
function Dict:setdefault(k,x)
  self[k] = rawget(self,k) or x
  return self[k]
end

-- Python: a.popitem() remove and return an arbitrary (key, value) pair
function Dict:popitem()
  local k,v = next(self)
  self[k] = nil
  return k,v
end

-- Python len(list) is not the same as getn, must count key-value pairs
len = Dict.len

-- test using: lua -f pydict.lua -test
if arg and arg[1]=="-test" then
  local prl = function(l) for i=1,getn(l) do write(l[i]) end print() end
  local prd = function(l) for k,v in l do write(k.."="..v..",") end print() end
  local dict = Dict:new{a=1,b=2,c=3}  prd(dict)
  dict["d"]=4 ; write("d=4: ") ; prd(dict)
  dict.e=5 ; write("e=5: ") ; prd(dict)
  print("dict length: "..dict:len())
  dict:del(3) ; write("del[3]: ") ; prd(dict)
  local d2 = dict:copy() ; write("copy: ") ; prd(d2)
  d2:clear() ; write("clear: ") ; prd(d2)
  print("length: "..d2:len())
  assert( d2:len()==0 )
  assert( dict:has_key("a") )
  print('dict:has_key("a") : '..dict:has_key("a"))
  write("items: ") ; print( getn(dict:items()) )
  write("keys: ") ; prl( dict:keys() )
  dict:update{ f=6,g=7 } ; write("dict:update{ f=6,g=7 } : ") ; prd(dict)
  write("values: ") ; prl( dict:values() )
  write('dict:get("z",26) : ') print(dict:get("z",26))
  write('dict:setdefault("y",25) : ') print(dict:setdefault("y",25))
  write('dict:popitem() : '..dict:popitem()..", ") ; prd(dict)
  local foo = Dict:new { len="vcbvcb" }  print(foo:len())  -- same name test
  -- print(foo["wont find this"]) -- test "key error"
end


另請參閱:PythonLists
RecentChanges · 喜好設定
編輯 · 歷史記錄
上次編輯時間為 2007 年 1 月 6 日上午 5:06 GMT (diff)