2

I want to achieve that calling foo(2*3) prints 2*3.

The reason is that I try to create a test framework for querying data files and I want to print the query statement with the assertion result.

I tried to get it work via the inspect module but I could not make it work.

wovano
  • 4,543
  • 5
  • 22
  • 49
user1235183
  • 3,002
  • 1
  • 27
  • 66

2 Answers2

2

In general, the answer is "no", since the value received by the function is the result of the expression 2*3, not the expression itself. However, in Python almost anything is possible if you really want it ;-)

For simple cases you could achieve this using the inspect module like this:

#!/usr/bin/env python3

import inspect


def foo(x):
    context = inspect.stack()[1].code_context[0]
    print(context)


def main():
    foo(2 * 3)


if __name__ == '__main__':
    main()

This will print:

    foo(2 * 3)

It would be trivial to get the part 2 * 3 from this string using a regular expression. However, if the function call is not on a single line, or if the line contains multiple statements, this simple trick will not work properly. It might be possible with more advanced coding, but I guess your use case is to simply print the expression in a test report or something like that? If so, this solution might be just good enough.

wovano
  • 4,543
  • 5
  • 22
  • 49
  • inspect.stack has a parameter context (default=1) https://docs.python.org/3/library/inspect.html#inspect.stack . There you can parameterize the number of lines the context contains. So you can make it work even for multi line statements. – user1235183 Jul 07 '20 at 06:41
  • @user1235183, correct, although it will be tricky to determine how many lines of context are necessary and to parse that code. You would have to deal with comments, line continuation characters, multiple calls of the function (how do you know which one is the correct one?), etc. So basically you would have to write a complete parser then. The `ast` module might be of help here, but personally I won't go down that road. – wovano Jul 07 '20 at 06:47
1

Because the expression is evaluated before it is passed to the function, it is not possible to print out the un-evaluated expression.

However, there is a possible workaround. You can instead pass the expression as a string and evaluate it inside the function using eval(). As a simple example:

def foo(expr):
    print(expr)
    return(eval(expr))

Please note however that using eval is considered bad practice.

A better solution is to simply pass a string as well as the expression, such as foo(2*3, "2*3").

Kexus
  • 659
  • 2
  • 6
  • 13
  • 1
    There are other alternatives too. For instance, if `foo` always expects a multiplication expression, it could take its arguments separately (`foo(2, 3)`). – Blckknght Jul 06 '20 at 15:40