If the code you are running prints to screen and you're calling it with root.tk.eval() you can't capture that. However, You can redefine what "puts" does in the tcl code and have it do whatever you want. This is part of the beauty of Tcl -- there are no reserved words.
Simply create a proc named "puts" in the tcl interpreter, though make sure it has the exact same interface (ie: respects "-nonewline", can write to files, etc). When the puts normally prints to the screen you can instead have it do whatever you want, such as write to a socket or merely return the string it's supposed to print.
Roughly (untested, and ignoring the case with -nonewline):
root.tk.eval('''
rename puts original_puts
proc puts {args} {
if {[llength $args] == 1} {
return "=> [lindex $args 0]"
} else {
eval original_puts $args
}
}
''')
foo = root.tk.eval('puts "hello, world"')
print foo
=> hello, world
It will require a little diligence to make sure you don't break the tcl code which expects a standard "puts" statement, but it's not that hard to do. Just make sure you have special cases for one argument, the first argument of "-nonewline", and where there are two arguments (file descriptor and string).
It might get complicated if you call eval and it does two puts statements, or does a puts and then some other code, since the result of the eval is the result of the last statement. However, you can work around that by having puts buffer its output to a global variable and then return the result of that variable each time you do an eval.
So, think outside the box a little and you can find a solution. Tcl is very flexible.