0

I'm using Tkinter module in python, and trying to pass varibales in python to tcl

I know I can pass variable like

tclsh = Tkinter.Tcl()
num = 1 
tclsh.eval("set num {}".format(1))

Is there any otherway I can do this ? Since I'm going to pass many variables, I hope to have an elegant way to pass the variables

Like in this post Pass Python variables to `Tkinter.Tcl().eval()`

But I tried this, it doesn't work for me

whtitefall
  • 631
  • 9
  • 16

2 Answers2

4

I don't think there's anyway to add variables to the tcl interepreter in bulk. However, instead of using eval and string formatting, you can use call. The advantage to call over eval is that call will take care of the details of properly quoting all of the arguments.

call lets you call tcl procs pretty much like you do in tcl, by providing each word as an argument. The example from your question would look like this:

tclsh.call("set", "num", num)

However, this will only work for fundamental datatypes like strings and numbers. There's no automatic conversion of objects such as lists and dictionaries to the underlying tcl data types.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
0

Here's a slightly neater version that wraps up access to Tcl's global variables as a Python class:

import tkinter

class TclGlobalVariables(object):
    def __init__(self, tclsh):
        self.tclsh = tclsh

    def __setattr__(self, name, value):
        if name == "tclsh":
            object.__setattr__(self, name, value)
        else:
            # The call method is perfect for this job!
            self.tclsh.call("set", "::" + name, str(value))

    def __getattr__(self, name):
        if name == "tclsh":
            return object.__getattr__(self, name)
        else:
            # Tcl's [set] with only one argument reads the variable
            return self.tclsh.call("set", "::" + name)

Demonstrating it:

tcl = TclGlobalVariables(tkinter.Tcl())
# Write to a Tcl variable
tcl.x = 123
# Read from it
print("From Python: x =", tcl.x)
# Show that it is really there by sending commands to the underlying Tcl interpreter
tcl.tclsh.eval('puts "From Tcl: x = $x"')
# Show that manipulations on the Tcl side are carried through
tcl.tclsh.eval('incr x 2')
print("From Python again: x =", tcl.x)
# Show that manipulations on the Python side are carried through
tcl.x += 3
tcl.tclsh.eval('puts "From Tcl again: x = $x"')

Which produces this output:

From Python: x = 123
From Tcl: x = 123
From Python again: x = 125
From Tcl again: x = 128

Note that this assumes that you are only accessing simple global variables on the Tcl side (not namespaced variables and not arrays) and doesn't handle type mapping. Deeper levels of mapping are possible… but get really complicated.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215