Capturing **vars() pattern in string formatting - python

I frequently find myself using the following pattern for string formatting.
a = 3
b = 'foo'
c = dict(mykey='myval')
#prints a is 3, b is foo, mykey is myval
print('a is {a}, b is {b}, mykey is {c[mykey]}'.format(**vars()))
That is, I often have the values I need to print in the local namespace, represented by a call to vars(). As I look over my code, however, it seems awfully unpythonic to be constantly repeating the .format(**vars()) pattern.
I'd like to create a function that will capture this pattern. It would be something like the following.
# doesn't work
def lfmt(s):
"""
lfmt (local format) will format the string using variables
in the caller's local namespace.
"""
return s.format(**vars())
Except that by the time I'm in the lfmt namespace, vars() is no longer what I want.
How can I write lfmt so that it executes vars() in the caller's namespace such that the following code would work as the example above?
print(lfmt('a is {a}, b is {b}, mykey is {c[mykey]}'))

Edit: In order for lfmt to work when called from different namespaces, you'll need the inspect module. Note, as the documentation warns, the inspect module may not be suitable for production code since it may not work with all implementations of Python
import inspect
def lfmt(s):
caller = inspect.currentframe().f_back
return s.format(**caller.f_locals)
a = 3
b = 'foo'
c = dict(mykey='myval')
print(lfmt('a is {a}, b is {b}, mykey is {c[mykey]}'))
# a is 3, b is foo, mykey is myval

You have to inspect the variables from the calling frames.
This will get you started:
import inspect
import pprint
def lfmt(s):
for frame in inspect.getouterframes(inspect.currentframe()):
f = frame[0]
print pprint.pformat(f.f_locals)
return '???'
if __name__ == '__main__':
a = 10
b = 20
c = 30
lfmt('test')

Here you are:
import sys
def lfmt(s):
"""
lfmt (local format) will format the string using variables
in the caller's local namespace.
"""
if hasattr(sys, "tracebacklimit") and sys.tracebacklimit == 0:
raise Exception, "failfailfail"
try:
raise ZeroDivisionError
except ZeroDivisionError:
f = sys.exc_info()[2].tb_frame.f_back
return s.format(**f.f_locals)
a = 5
somestring = "text"
print lfmt("{a} {somestring}")
The fact that it works doesn't mean you should use it. This is what developers call "major hack", usually shipped with a comment "XXX fix me XXX".

Is it so bad to type ,vars each time you call the function?
def lfmt(s,v):
"""
lfmt (local format) will format the string using variables
from the dict returned by calling v()"""
return s.format(**v())
print(lfmt('a is {a}, b is {b}, mykey is {c[mykey]}',vars))

You could also use sys instead of inspect, but I don't know if it has the same problem with different implementations as inspect has.
import sys
def lfmt(s):
caller = sys._getframe(1)
return s.format(**caller.f_locals)
This is as far as I got: Python string interpolation implementation

Related

How can we print the variable name along with its value in python, which will be useful during debugging?

I have written something like this multiple times:
print 'customer id: ', customerId
I want to have a function which prints variable name along with the value
>>myprint(customerId)
>>customerId: 12345
Doing exactly what you require involves a O(n) lookup in the symbol table, which is terrible IMHO.
If you can pass the string corresponding to the variable name, you can do this:
import sys
def myprint(name, mod=sys.modules[__name__]):
print('{}: {}'.format(name, getattr(mod, name)))
Test:
a=535
b='foo'
c=3.3
myprint('a')
myprint('b')
myprint('c')
Will print:
a: 535
b: foo
c: 3.3
You can use it also for printing variables from another module by passing the second argument, e.g.:
>>> import os
>>> myprint('pathsep', os)
pathsep: :
Basically you need to hand-type the variable name into your helper function's argument every time you call it, which makes it the same as directly formatting the strings into a printed message.
Another possible (useless?) heck can be the following:
import re
regex = re.compile("__(.+)")
def check_value(checkpoint_name):
print "============"
print checkpoint_name
print "============"
for variable_name, variable_value in globals().items():
if regex.match(variable_name) is None:
print "%s\t:\t%s" % (variable_name, str(variable_value))
print "============"
,which prints all non-system-protected, declared variables in global scope per call. To call the function, do
a = 0
check_value("checkpoint after definition of a")
b = 1
check_value("checkpoint after definition of b")
Feel free to customize the function for your need. I just came up with this, not sure if this works the way you want...

How to use Overloading in Iron Python?

I wanted to use overloading in Iron Python but seems it's not working :
import sys
import clr
def af(a, b):
c = a+b
print c
return c
def af(j):
y = j*j
print y
return y
af(6,7)
af(5)
I get a error =\
Is there any way to use overloading ?
my purpose is to write a function : foo(doAction,numTimes)
when by default if I use foo(action): it will do it once,
or I'll write : foo(action,6)
thanks a lot!!!
IronPython might run on the CLR but that doesn't make it C#. In any kind of Python, you can only define a function once. Defining a function is really just assigning to a name, so in your code you assign a function to af, then assign another one to the same name, so the first one is simply discarded.
The way to do this in Python is via default arguments:
def aj(a, b=None):
if b is not None:
result = a + b
else:
result = a * a
print result
return result
For your actual use case of course you can define numtimes with a default of 1:
def foo(action, numtimes=1):
# whatever

How to find the name of a variable that was passed to a function?

In C/C++, I have often found it useful while debugging to define a macro, say ECHO(x), that prints out the variable name and its value (i.e. ECHO(variable) might print variable 7). You can get the variable name in a macro using the 'stringification' operator # as described here. Is there a way of doing this in Python?
In other words, I would like a function
def echo(x):
#magic goes here
which, if called as foo=7; echo(foo) (or foo=7; echo('foo'), maybe), would print out foo 7. I realise it is trivial to do this if I pass both the variable and its name to the function, but I use functions like this a lot while debugging, and the repetition always ends up irritating me.
Not really solution, but may be handy (anyway you have echo('foo') in question):
def echo(**kwargs):
for name, value in kwargs.items():
print name, value
foo = 7
echo(foo=foo)
UPDATE: Solution for echo(foo) with inspect
import inspect
import re
def echo(arg):
frame = inspect.currentframe()
try:
context = inspect.getframeinfo(frame.f_back).code_context
caller_lines = ''.join([line.strip() for line in context])
m = re.search(r'echo\s*\((.+?)\)$', caller_lines)
if m:
caller_lines = m.group(1)
print caller_lines, arg
finally:
del frame
foo = 7
bar = 3
baz = 11
echo(foo)
echo(foo + bar)
echo((foo + bar)*baz/(bar+foo))
Output:
foo 7
foo + bar 10
(foo + bar)*baz/(bar+foo) 11
It has the smallest call, but it's sensitive to newlines, e.g.:
echo((foo + bar)*
baz/(bar+foo))
Will print:
baz/(bar+foo)) 11
def echo(x):
import inspect
print "{0}: {1}".format(x, inspect.stack()[1][0].f_locals[x])
y = 123
echo('y')
# 'y: 123'
See also: https://stackoverflow.com/a/2387854/16361
Note that this can cause GC issues:
http://docs.python.org/library/inspect.html#the-interpreter-stack
It will also turn off people who have been burned by messing with frames, and may leave a bad taste in your mouth. But it will work.
Here's a solution that has you type a bit more to call it. It relies on the locals built-in function:
def print_key(dictionary, key):
print key, '=', dictionary[key]
foo = 7
print_key(locals(), 'foo')
An echo with the semantics you mentioned is also possible, using the inspect module. However, do read the warnings in inspect's documentation. This is an ugly non-portable hack (it doesn't work in all implementations of Python). Be sure to only use it for debugging.
The idea is to look into the locals of the calling function. The inspect module allows just that: calls are represented by frame objects linked together by the f_back attribute. Each frame's local and global variables are available (there are also builtins, but you're unlikely to need to print them).
You may want to explicitly delete any references frame objects to prevent reference cycles, as explained in inspect docs, but this is not strictly necessary – the garbage collection will free them sooner or later.
import inspect
def echo(varname):
caller = inspect.currentframe().f_back
try:
value = caller.f_locals[varname]
except KeyError:
value = caller.f_globals[varname]
print varname, '=', value
del caller
foo = 7
echo('foo')

Go through a number of functions in Python

I have an unknown number of functions in my python script (well, it is known, but not constant) that start with site_...
I was wondering if there's a way to go through all of these functions in some main function that calls for them.
something like:
foreach function_that_has_site_ as coolfunc
if coolfunc(blabla,yada) == true:
return coolfunc(blabla,yada)
so it would go through them all until it gets something that's true.
thanks!
The inspect module, already mentioned in other answers, is especially handy because you get to easily filter the names and values of objects you care about. inspect.getmembers takes two arguments: the object whose members you're exploring, and a predicate (a function returning bool) which will accept (return True for) only the objects you care about.
To get "the object that is this module" you need the following well-known idiom:
import sys
this_module = sys.modules[__name__]
In your predicate, you want to select only objects which are functions and have names that start with site_:
import inspect
def function_that_has_site(f):
return inspect.isfunction(f) and f.__name__.startswith('site_')
With these two items in hand, your loop becomes:
for n, coolfunc in inspect.getmembers(this_module, function_that_has_site):
result = coolfunc(blabla, yada)
if result: return result
I have also split the loop body so that each function is called only once (which both saves time and is a safer approach, avoiding possible side effects)... as well as rewording it in Python;-)
Have you tried using the inspect module?
http://docs.python.org/library/inspect.html
The following will return the methods:
inspect.getmembers
Then you could invoke with:
methodobjToInvoke = getattr(classObj, methodName)
methodobj("arguments")
This method goes through all properties of the current module and executes all functions it finds with a name starting with site_:
import sys
import types
for elm in dir():
f = getattr(sys.modules[__name__], elm)
if isinstance(f, types.FunctionType) and f.__name__[:5] == "site_":
f()
The function-type check is unnecessary if only functions are have names starting with site_.
def run():
for f_name, f in globals().iteritems():
if not f_name.startswith('site_'):
continue
x = f()
if x:
return x
It's best to use a decorator to enumerate the functions you care about:
_funcs = []
def enumfunc(func):
_funcs.append(func)
return func
#enumfunc
def a():
print 'foo'
#enumfunc
def b():
print 'bar'
#enumfunc
def c():
print 'baz'
if __name__ == '__main__':
for f in _funcs:
f()
Try dir(), globals() or locals(). Or inspect module (as mentioned above).
def site_foo():
pass
def site_bar():
pass
for name, f in globals().items():
if name.startswith("site_"):
print name, f()

Get functions called in a Python expression

I have a database that holds the name of Python functions and a string for their code. I want the user to be able to enter a Python code and see the result. The problem is that I need to know the names of the functions they call in order to retrieve the code from the database. For instance, if they enter cubic_fit(1, 2, get_data()), I need a way to get the function names cubic_fit and get_data. Is there a good way to do this?
The built-in function compile will do that for you exactly:
>>> compile("cubic_fit(1, 2, get_data())", '<string>', 'eval').co_names
('cubic_fit', 'get_data')
And it is safe to run. No code is actually being executed just compiled.
A quick example to you started. Note that you'll be expecting valid python semantics for this to work.
You can extend this to also parse your arguments...
import token, tokenize, StringIO
def extract_names(src):
rawstr = StringIO.StringIO(unicode(src))
tokens = tokenize.generate_tokens(rawstr.readline)
for i, item in enumerate(tokens):
toktype, toktext, (srow,scol), (erow,ecol), line = item
if token.tok_name[toktype] == 'NAME':
print 'name:', toktext
extract_names("cubic_fit(1, 2, get_data())")
# --> output:
# name: cubic_fit
# name: get_data
If you just want the names, then the compile() and co_names method will work best.
You also might take advantage of the capability of eval() to use any mapping object as its locals parameter. You could create a mapping object to look up and compile the objects from your database as needed by eval().
Example:
class LookitUp(object):
def __init__(self):
# simulate some data
self.d = { "foo": "def foo(a):\n return a + 2"}
def __getitem__(self,key):
localdict = {}
c = compile(self.d.get(key,""),"<string>","exec")
eval(c,globals(),localdict)
return localdict[key]
d = LookitUp()
def bar(a):
return a - 1
print "foo from database :",eval("foo(3)",globals(), d)
print "bar from globals():",eval("bar(3)",globals(), d)
print "foo(bar(3)) :",eval("foo(bar(3))",globals(), d)
Result:
foo from database : 5
bar from globals(): 2
foo(bar(3)) : 4
You may need to modify based on what your source in the database looks like, but it's a place to start.

Categories

Resources