Returning actual argument expression to a function call?

P

Paddy

Hi,
# If I have a function definition
def f1(arg):
global capturecall
if capturecall:
...
do_normal_stuff(arg)

# and its later use:
def f2():
...
return f1(a and (b or c))

# I would like to do:
capturecall = False
result = f2()
# And get the equivalent of do_normal_stuff(a and(b or c))

# But also to do:
capturecall = True
result = f2()
# And get the same result, but also save the actual
# calling arguments to f1 either as a string:
# "a and (b or c))"
# Or a code object computing a and(b or c)


# I caould change f1 to expect a function instead and do:
def f1b(arg):
global capturecall
if capturecall:
save(arg)
return do_normal_stuff(arg())

# And then use it like this:
def f2b():
...
return f1b(lambda : (a and (b or c)) )

# The problem is that for my application to work,
# Python newbies would have to write lambda when they
# know they are after the result. Its my program
# that would require the lambda (or def), which
# is a distraction from their problem.

Any ideas on implementing f1 so I can do f2?

Thanks in advance, Paddy.


P.S. You might also have multiple calls where I
would need to capture each individual argument
expression of f1 e.g:
def f3():
...
return f1(a and b) or e or f1(c and d)
 
S

Steven D'Aprano

Hi,
# If I have a function definition ....
# The problem is that for my application to work,
# Python newbies would have to write lambda when they
# know they are after the result.

I don't understand why you think this is the case.

Its my program
# that would require the lambda (or def), which
# is a distraction from their problem. ....
Any ideas on implementing f1 so I can do f2?

I've read your post three times now, and I'm still not absolutely sure
what you're trying to accomplish.

I think you want something like this:

You have a function f1(*args) which returns a result. You want a global
flag that tells f1 to stick it's arguments in a global variable. Am I
close?

If so, something like this should work:

# Define someplace to store the arguments.
last_args = (None, None)
# And a flag.
capturecall = True

# A decorator to wrap a function.
def capture_args(func):
def f(*args, **kwargs):
if capturecall:
global last_args
last_args = (args, kwargs)
return func(*args, **kwargs)
f.__name__ = "capturing_" + func.__name__
return f



Now you can do this:
.... return x + y
........ def f2(x):
.... return 2**x
....((1.3999999999999999,), {})



In the second example, if you are trying to capture the expression "0.4
+1", I don't think that is possible. As far as I know, there is no way
for the called function to find out how its arguments were created. I
think if you need that, you need to create your own parser.
 
G

Gabriel Genellina

Hi,
# If I have a function definition
def f1(arg):
global capturecall
if capturecall:
...
do_normal_stuff(arg)

# and its later use:
def f2():
...
return f1(a and (b or c))

# But also to do:
capturecall = True
result = f2()
# And get the same result, but also save the actual
# calling arguments to f1 either as a string:
# "a and (b or c))"
# Or a code object computing a and(b or c)

Would be enough to have the source line text?

<code test1.py>
def extract_caller_info():
import sys, traceback
return traceback.extract_stack(sys._getframe(2), limit=1)

def f1(arg):
if capturecall:
print extract_caller_info()
# do_normal_stuff(arg)

def f2():
a,b,c = 1,0,3
return f1(a and (b or c))

capturecall = True
result = f2()
</code>

output is like this:
[('test1.py', 12, 'f2', 'return f1(a and (b or c))')]

source file name, line number, function name, source line text.
P.S. You might also have multiple calls where I
would need to capture each individual argument
expression of f1 e.g:
def f3():
...
return f1(a and b) or e or f1(c and d)

Tell your users that they'll have better results if those two calls are
split on different lines:

def f3():
return (f1(a and b)
or e
or f1(c and d))

Output:
[('test1.py', 18, 'f3', 'return (f1(a and b)')]
[('test1.py', 20, 'f3', 'or f1(c and d))')]
 
P

Paddy

In the second example, if you are trying to capture the expression "0.4
+1", I don't think that is possible. As far as I know, there is no way
for the called function to find out how its arguments were created. I
think if you need that, you need to create your own parser.

Unfortunately Steven, its exactly the expression that I want
rather than the expression result.

Thanks for your attempt, and I will try and make myself clearer
in the future (allthough I did take time over my initial post).

- Paddy.
 
P

Paddy

En Sat, 10 Nov 2007 03:03:00 -0300, Paddy <[email protected]>
escribió:


Hi,
# If I have a function definition
def f1(arg):
global capturecall
if capturecall:
...
do_normal_stuff(arg)
# and its later use:
def f2():
...
return f1(a and (b or c))
# But also to do:
capturecall = True
result = f2()
# And get the same result, but also save the actual
# calling arguments to f1 either as a string:
# "a and (b or c))"
# Or a code object computing a and(b or c)

Would be enough to have the source line text?

<code test1.py>
def extract_caller_info():
import sys, traceback
return traceback.extract_stack(sys._getframe(2), limit=1)

def f1(arg):
if capturecall:
print extract_caller_info()
# do_normal_stuff(arg)

def f2():
a,b,c = 1,0,3
return f1(a and (b or c))

capturecall = True
result = f2()
</code>

output is like this:
[('test1.py', 12, 'f2', 'return f1(a and (b or c))')]

source file name, line number, function name, source line text.
P.S. You might also have multiple calls where I
would need to capture each individual argument
expression of f1 e.g:
def f3():
...
return f1(a and b) or e or f1(c and d)

Tell your users that they'll have better results if those two calls are
split on different lines:

def f3():
return (f1(a and b)
or e
or f1(c and d))

Output:
[('test1.py', 18, 'f3', 'return (f1(a and b)')]
[('test1.py', 20, 'f3', 'or f1(c and d))')]


Thanks Gabriel, that will alow me to move forward.
 
P

Piet van Oostrum

Paddy said:
P> Hi,
P> # If I have a function definition
P> def f1(arg):
P> global capturecall
P> if capturecall:
P> ...
P> do_normal_stuff(arg)
P> # and its later use:
P> def f2():
P> ...
P> return f1(a and (b or c))
P> # I would like to do:
P> capturecall = False
P> result = f2()
P> # And get the equivalent of do_normal_stuff(a and(b or c))
P> # But also to do:
P> capturecall = True
P> result = f2()
P> # And get the same result, but also save the actual
P> # calling arguments to f1 either as a string:
P> # "a and (b or c))"
P> # Or a code object computing a and(b or c)

P> # I caould change f1 to expect a function instead and do:
P> def f1b(arg):
P> global capturecall
P> if capturecall:
P> save(arg)
P> return do_normal_stuff(arg())
P> # And then use it like this:
P> def f2b():
P> ...
P> return f1b(lambda : (a and (b or c)) )
P> # The problem is that for my application to work,
P> # Python newbies would have to write lambda when they
P> # know they are after the result. Its my program
P> # that would require the lambda (or def), which
P> # is a distraction from their problem.
P> Any ideas on implementing f1 so I can do f2?

With Python this can't be done without either quoting the expression (make
a string out of it) or using a lambda. Lisp and C# can do this kind of thing.
 
P

Paddy

With Python this can't be done without either quoting the expression (make
a string out of it) or using a lambda. Lisp and C# can do this kind of thing.

<WarpedHumour>
I'd like to propose we add '(<expr>) to Python. Pronounced tick-
brackets, it
surrounds an expression which is compiled into an anonymous function.

I have not thought this through apart from knowing that this is one
more
step towards Lisp heaven and submit no code as the implementation
will be trivial ;-)

Of course if my suggestion is not welcomed with open arms then this
is
Pythons last chance to escape terminal decline....
<WeftedHumour>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top