在 Python 中解析从 TCL 返回的关联数组
Parsing associate array returned from TCL in Python
我有一项要求是从 Python 调用 TCL 脚本。我的要求是从 python 调用 TCL proc。 TCL proc returns 结果作为一个数组。我需要解析 Python 中返回的数组以形成字典。下面是一个工作代码。有没有更有效的方法来做同样的事情?
Python代码
import tkinter
import shlex
r=tkinter.Tk()
r.tk.eval('source proc.tcl')
arr = []
arr = r.tk.eval('processarray arr')
print(arr)
j=0
for i in arr.split(' '):
print(i)
d = {}
ssplit = arr.split()
print(len(ssplit))
print(len(ssplit)/2)
j=int(len(ssplit)/2)
k=0
for i in range (j):
key = ssplit[k]
d[key] = ssplit[k+1]
k += 2
print(d)
TCL代码
proc processarray { $arr } {
array set arr " arrlist 25645"
set arr(0) "11"
set arr(1) "10"
set arr(2) "20"
set arr(3) "30"
set arr(4) "40"
return [array get arr]
}
预期结果
{'4': '40', '0': '11', '1': '10', 'arrlist': '25645', '2': '20', '3': '30'}
我从未使用过 TCL,但我 运行 此代码并从 TCL
4 40 0 11 1 10 arrlist 25645 2 20 3 30
我可以使用 range(len())
和 [i:i+2]
.
将其转换为字典
也许使用 range(len())
并不流行,但在这种情况下它会非常有用。
import tkinter
r = tkinter.Tk()
r.tk.eval('source proc.tcl')
arr = []
arr = r.tk.eval('processarray arr')
#print(arr)
items = arr.split()
data = {}
for i in range(0, len(items), 2):
key, val = items[i:i+2]
data[key] = val
print(data)
结果
{'4': '40', '0': '11', '1': '10', 'arrlist': '25645', '2': '20', '3': '30'}
编辑: 我也可以使用 iter()
和 zip()
import tkinter
r = tkinter.Tk()
r.tk.eval('source proc.tcl')
arr = []
arr = r.tk.eval('processarray arr')
#print(arr)
items = arr.split()
data = {}
it = iter(items) # create iterator
for key, val in zip(it, it): # use `zip()` to get two elements from list
data[key] = val
print(data)
Python 的 Tkinter 包没有很好的文档记录,所以我不得不为此深入研究源代码...
有一个 _splitdict()
函数,给定一个包含偶数个 tcl 单词的字符串,例如 return 由 Tcl 的 array get
编辑,return 它作为python 字典。我真的不知道 Python,但我敢打赌下划线和笨拙的界面意味着它是内部的,你不应该使用它。但似乎没有 public 替代方案:
>>> import tkinter
>>> tcl = tkinter.Tcl()
>>> tkinter._splitdict(tcl, 'foo 1 bar 2 baz {3 4}')
{'bar': '2', 'foo': '1', 'baz': '3 4'}
或者,您可以只编写自己的函数来执行它在内部执行的操作。重要的一点是 tk.splitlist('some string')
,它根据 tcl 规则将其参数分解为单词 - 需要正确处理空格或列表中单个单词中的任何类似内容 array get
return s(示例见上)。
A(未测试)精简版。原文可见in the Python source
def splitdict(v):
"""Return a properly formatted dict built from Tcl list pairs.
Tcl list is expected to contain an even number of elements.
"""
t = r.tk.splitlist(v)
if len(t) % 2:
raise RuntimeError('Tcl list representing a dict is expected '
'to contain an even number of elements')
it = iter(t)
dict = {}
for key, value in zip(it, it):
key = str(key)
dict[key] = value
return dict
通过使用 call
而不是 eval
,您可以为自己简化很多事情。
import tkinter
r = tkinter.Tk()
# Putting the Tcl code I've used inline
r.tk.eval("""
proc processarray { $arr } {
array set arr " arrlist 25645"
set arr(0) "11"
set arr(1) "10"
set arr(2) "20"
set arr(3) "30"
set arr(4) "40"
# CRITICAL! Must return a list, not a dict
return [list {*}[array get arr]]
}
""")
r.tk.wantobjects(True) # This is the default setting...
arr = r.tk.call('processarray', 'arr')
# This is a bit of magic to turn a pair-list into a dict, based on
#
c = {k: v for k, v in zip(arr[:-1:2], arr[1::2])}
print(c)
这里的关键是:
- 我们使用
call
(这是调用单个命令和保留参数边界等的更好选择),
- 我们有
wantobjects(True)
(实际上默认开启),
- 我们让 Tcl 端强制结果成为一个列表 (
[list {*}…]
) and 我们 post-处理 Python 端的列表以获取字典(这是因为 Tkinter 出于某种原因不为您进行字典映射;这是 Tkinter bug/missing 功能)。
当我运行这个时,我得到这个输出:
{4: '40', 0: '11', 1: '10', 'arrlist': '25645', 2: '20', 3: '30'}
符合预期; Tcl 的数组从来都不是保序的,而且据记载也不是这样。 (我不知道为什么 Tkinter 将一些键转换为 int
s。)
我有一项要求是从 Python 调用 TCL 脚本。我的要求是从 python 调用 TCL proc。 TCL proc returns 结果作为一个数组。我需要解析 Python 中返回的数组以形成字典。下面是一个工作代码。有没有更有效的方法来做同样的事情?
Python代码
import tkinter
import shlex
r=tkinter.Tk()
r.tk.eval('source proc.tcl')
arr = []
arr = r.tk.eval('processarray arr')
print(arr)
j=0
for i in arr.split(' '):
print(i)
d = {}
ssplit = arr.split()
print(len(ssplit))
print(len(ssplit)/2)
j=int(len(ssplit)/2)
k=0
for i in range (j):
key = ssplit[k]
d[key] = ssplit[k+1]
k += 2
print(d)
TCL代码
proc processarray { $arr } {
array set arr " arrlist 25645"
set arr(0) "11"
set arr(1) "10"
set arr(2) "20"
set arr(3) "30"
set arr(4) "40"
return [array get arr]
}
预期结果
{'4': '40', '0': '11', '1': '10', 'arrlist': '25645', '2': '20', '3': '30'}
我从未使用过 TCL,但我 运行 此代码并从 TCL
4 40 0 11 1 10 arrlist 25645 2 20 3 30
我可以使用 range(len())
和 [i:i+2]
.
将其转换为字典
也许使用 range(len())
并不流行,但在这种情况下它会非常有用。
import tkinter
r = tkinter.Tk()
r.tk.eval('source proc.tcl')
arr = []
arr = r.tk.eval('processarray arr')
#print(arr)
items = arr.split()
data = {}
for i in range(0, len(items), 2):
key, val = items[i:i+2]
data[key] = val
print(data)
结果
{'4': '40', '0': '11', '1': '10', 'arrlist': '25645', '2': '20', '3': '30'}
编辑: 我也可以使用 iter()
和 zip()
import tkinter
r = tkinter.Tk()
r.tk.eval('source proc.tcl')
arr = []
arr = r.tk.eval('processarray arr')
#print(arr)
items = arr.split()
data = {}
it = iter(items) # create iterator
for key, val in zip(it, it): # use `zip()` to get two elements from list
data[key] = val
print(data)
Python 的 Tkinter 包没有很好的文档记录,所以我不得不为此深入研究源代码...
有一个 _splitdict()
函数,给定一个包含偶数个 tcl 单词的字符串,例如 return 由 Tcl 的 array get
编辑,return 它作为python 字典。我真的不知道 Python,但我敢打赌下划线和笨拙的界面意味着它是内部的,你不应该使用它。但似乎没有 public 替代方案:
>>> import tkinter
>>> tcl = tkinter.Tcl()
>>> tkinter._splitdict(tcl, 'foo 1 bar 2 baz {3 4}')
{'bar': '2', 'foo': '1', 'baz': '3 4'}
或者,您可以只编写自己的函数来执行它在内部执行的操作。重要的一点是 tk.splitlist('some string')
,它根据 tcl 规则将其参数分解为单词 - 需要正确处理空格或列表中单个单词中的任何类似内容 array get
return s(示例见上)。
A(未测试)精简版。原文可见in the Python source
def splitdict(v):
"""Return a properly formatted dict built from Tcl list pairs.
Tcl list is expected to contain an even number of elements.
"""
t = r.tk.splitlist(v)
if len(t) % 2:
raise RuntimeError('Tcl list representing a dict is expected '
'to contain an even number of elements')
it = iter(t)
dict = {}
for key, value in zip(it, it):
key = str(key)
dict[key] = value
return dict
通过使用 call
而不是 eval
,您可以为自己简化很多事情。
import tkinter
r = tkinter.Tk()
# Putting the Tcl code I've used inline
r.tk.eval("""
proc processarray { $arr } {
array set arr " arrlist 25645"
set arr(0) "11"
set arr(1) "10"
set arr(2) "20"
set arr(3) "30"
set arr(4) "40"
# CRITICAL! Must return a list, not a dict
return [list {*}[array get arr]]
}
""")
r.tk.wantobjects(True) # This is the default setting...
arr = r.tk.call('processarray', 'arr')
# This is a bit of magic to turn a pair-list into a dict, based on
#
c = {k: v for k, v in zip(arr[:-1:2], arr[1::2])}
print(c)
这里的关键是:
- 我们使用
call
(这是调用单个命令和保留参数边界等的更好选择), - 我们有
wantobjects(True)
(实际上默认开启), - 我们让 Tcl 端强制结果成为一个列表 (
[list {*}…]
) and 我们 post-处理 Python 端的列表以获取字典(这是因为 Tkinter 出于某种原因不为您进行字典映射;这是 Tkinter bug/missing 功能)。
当我运行这个时,我得到这个输出:
{4: '40', 0: '11', 1: '10', 'arrlist': '25645', 2: '20', 3: '30'}
符合预期; Tcl 的数组从来都不是保序的,而且据记载也不是这样。 (我不知道为什么 Tkinter 将一些键转换为 int
s。)