Python 字典

lua-users home
wiki

[!] 版本说明: 以下代码适用于旧版本的 Lua,Lua 4。某些使用的功能,例如标签方法 (settagmethod),在 Lua 5 中不再存在,但已被元方法取代。

简介

Lua 的 table 类型是一个多用途容器,介于 Python 的列表和字典类型之间。以下列表模拟了 Python 的字典。有关此处实现内容的详细信息,请参阅 Python 映射类型的文档 [1]。有关更多信息,请参阅 Python 列表类和方法。该脚本是为 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 )
这将阻止用户数据和字典实现之间的冲突。-- NDT

抱歉,这不会阻止冲突。您只是交换了优先级;冲突仍然存在。现在 foo:len() 将返回 1,但 foo.len 将返回一个函数,而不是存储的值“vcbvcb”。顺便说一句,Python 列表 仅能正常工作,因为用户索引(始终为数字)和方法(始终为字符串)之间没有冲突。-- ET

代码

-- Emulation of Python dictionaries
-- Nick Trout -- thanks to lhf & ET
-- See https://www.pythonlang.cn/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


另请参阅:Python 列表
最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2007 年 1 月 6 日凌晨 5:06 GMT (差异)