Is this possible in Python?

A

alainpoint

Hi

I wonder if Python is capable of the following: define a function which
returns its argument.
I mean:
def magic_function(arg):
...... some magic code ...

that behaves the following way:

assert magic_function(3+4)=="3+4"
assert magic_function([i for i in range(10)])=="i for i in range(10)]"

It is not trivial at all and might require some bytecode hacking that i
am unable to do myself BUT you are the experts ;-)

Alain
 
P

Paul Rubin

assert magic_function(3+4)=="3+4"
assert magic_function([i for i in range(10)])=="i for i in range(10)]"

It is not trivial at all and might require some bytecode hacking that i
am unable to do myself BUT you are the experts ;-)

Guhhh... you'd want to use the traceback system and reach back into
the source code to get and parse the statement that called the magic
function, sort of like a debugger does. I don't think messing with
the bytecode would help.
 
A

Azolex

Paul said:
assert magic_function(3+4)=="3+4"
assert magic_function([i for i in range(10)])=="i for i in range(10)]"

It is not trivial at all and might require some bytecode hacking that i
am unable to do myself BUT you are the experts ;-)

Guhhh... you'd want to use the traceback system and reach back into
the source code to get and parse the statement that called the magic
function, sort of like a debugger does.

That's one way
I don't think messing with
the bytecode would help.

Well, the following package

http://packages.debian.org/stable/python/decompyle

might permit something like that.
 
K

Kay Schluehr

Hi

I wonder if Python is capable of the following: define a function which
returns its argument.
I mean:
def magic_function(arg):
...... some magic code ...

that behaves the following way:

assert magic_function(3+4)=="3+4"
assert magic_function([i for i in range(10)])=="i for i in range(10)]"

It is not trivial at all and might require some bytecode hacking that i
am unable to do myself BUT you are the experts ;-)

Alain

Storing arguments away before they are evaluated doesn't work in
Python. You have to hack the compiler in order to access the parsetree.
You might take a look at the compiler package of the standard library
that enables access to ASTs. Thus you could define lazy evaluation and
just-in-time compilation of some particular ASTs. I do not recommend
doing this for real purposes, but it is a good excercise and sooner or
later you become an expert yourself :)

Kay
 
D

Dennis Lee Bieber

that behaves the following way:

assert magic_function(3+4)=="3+4"

Unlikely... The only argument being passed to the function itself is
a reference to the integer value 7... The 3+4 has been evaluated
/before/ the function is called.
--
 
A

alainpoint

Kay said:
Storing arguments away before they are evaluated doesn't work in
Python. You have to hack the compiler in order to access the parsetree.
You might take a look at the compiler package of the standard library
that enables access to ASTs. Thus you could define lazy evaluation and
just-in-time compilation of some particular ASTs. I do not recommend
doing this for real purposes, but it is a good excercise and sooner or
later you become an expert yourself :)

Kay

I made some investigation and reached a (partial) solution to my
problem. It is inspired from a cookbook recipe but it only works for
generator expressions.:
import tokenize
import token
def magic_function(s):
cursor = None # to be set to the cursor of the connection
return_type = object # can be set to dict or list
_iterating = False # used in next()
readline = open(s.gi_frame.f_code.co_filename).readline
first_line = s.gi_frame.f_code.co_firstlineno
flag = False
source = '' # the source code
for t in
tokenize.generate_tokens(open(s.gi_frame.f_code.co_filename).readline):
# check all tokens until the last parenthesis is closed
t_type,t_string,(r_start,c_start),(r_end,c_end),line = t
t_name = token.tok_name[t_type]
if r_start == first_line:
if t_name == 'NAME' and t_string=="magic_function":
flag = True
res = t_string
start = 0 # number of parenthesis
continue
if flag:
source += ' '+t_string
if t_name == 'OP':
if t_string=='(':
start += 1
elif t_string == ')':
start -= 1
if start == 0:
break
return source[2:-2]

assert magic_function(i+2 for i in [1,2])=="i+2 for i in [1,2]"
or
print magic_function(i+2 for i in [1,2])

A general solution is possible and i am sure there are people around
that will provide such a solution

Alain
 
R

Ron Garret

Hi

I wonder if Python is capable of the following: define a function which
returns its argument.
I mean:
def magic_function(arg):
...... some magic code ...

that behaves the following way:

assert magic_function(3+4)=="3+4"
assert magic_function([i for i in range(10)])=="i for i in range(10)]"

It is not trivial at all and might require some bytecode hacking that i
am unable to do myself BUT you are the experts ;-)

Alain

You probably want to learn Lisp, where what you want to do is trivial:

(defmacro magic (arg) arg)

rg
 
T

Terry Reedy

Hi

I wonder if Python is capable of the following: define a function which
returns its argument.
I mean:
def magic_function(arg):
...... some magic code ...

that behaves the following way:

assert magic_function(3+4)=="3+4"
assert magic_function([i for i in range(10)])=="i for i in range(10)]"

The arguments to Python functions are Python objects. In order to return
the argument as a string, you must pass it as a string.
def magic(s): return s, eval(s)
magic('3+4') ('3+4', 7)
magic('[i**2 for i in [1,2,3]]')
('[i**2 for i in [1,2,3]]', [1, 4, 9])

Terry Jan Reedy
 
C

Caleb Hattingh

Hi

I don't think this is what you want (a string representation of the
argument passed to a function as that argument is at runtime is way
beyond my abilities), but this can retrieve the literal text in the
function call as it appears in the .py file, assuming you have the .py
file available and not just the .pyc:

### Call this file "pyfunargtest.py"
def fun(i):
pass

fun(8+7)

def test():
fname = 'pyfunargtest.py'
testfunname = 'f'
flines = open(fname,'r').readlines()
for i in flines:
if i.find(testfunname)>-1 and i.find('def '+testfunname)==-1:
s = i
break
leftbracketposition = s.find('(')
rightbracketposition = s.find(')')
arg = s[leftbracketposition+1:rightbracketposition]
return arg

print test()
### Output:
# 8+7
 
A

alainpoint

Hello again,
I am disappointed. You are the experts, you've got to try harder ;-)
What i want is a generalisation of this tiny function:
import tokenize
import token
def magic_function(s):
readline = open(s.gi_frame.f_code.co_filename).readline
for t in
tokenize.generate_tokens(open(s.gi_frame.f_code.co_filename).readline):
t_type,t_string,(r_start,c_start),(r_end,c_end),line = t
if r_start == s.gi_frame.f_code.co_firstlineno:
if t_string=="magic_function":
args= line.split(t_string)
arg=args[1]
return arg
# returns its own argument !
print magic_function(i+2 for i in [1,2])

There ought to be a way to make it work for more than generator
expressions !!!
 
K

Kent Johnson

Hello again,
I am disappointed. You are the experts, you've got to try harder ;-)
What i want is a generalisation of this tiny function:

Why? Maybe we can find a better way...

Kent
 
A

alainpoint

Hi Kent,
My intention is to be able to retrieve any line of code in a running
program, in the following way:
def magic_funct(s):
for line in file(s.gi_frame.f_code.co_filename):
print line
magic_funct(i for i in [1,2,3])

I just find it stupid to be obliged to use a generator expression, just
because it has got the gi_frame attribute. Such a kind of introspection
can be very useful.
I don't want a better way, i just want a solution to the problem as
described!

Alain
 
P

Paul Rubin

I don't want a better way, i just want a solution to the problem as
described!

I once did something like:

try:
raise ValueError
except ValueError, e:
pass

then get the traceback object out of e, and snarf the relevant source
line as mentioned before.
 
F

Fredrik Lundh

I don't want a better way, i just want a solution to the problem as
described!

any special reason you cannot use Python to write Python programs,
instead of demanding that someone else wastes time inventing a non-
portable solution to a braindead problem?

what's wrong with you?

</F>
 
F

Fredrik Lundh

jalanb said:

which only works if 1) you're using a Python implementation that supports
those attributes, 2) the source code is available, 3) the expression is written
on a single line, and 4) you don't use confusing comments after the function
call (and probably some more things I cannot think of right now).

perfectly valid Python constructs like

out(
temp
)

or

out(temp) # XXX: should use gettemp() instead

breaks the function.
Especially the "need to know" presentation, which is cute

indeed.

</F>
 
K

Kay Schluehr

jalanb said:
You might like the version here:
http://www.jorendorff.com/toys/out.html

Especially the "need to know" presentation, which is cute

Thank you for the tip.
Meanwhile, I found a shorter solution to my problem:
def magic(arg):
import inspect
return inspect.stack()[1][4][0].split("magic")[-1][1:-1]

assert magic(3+4)=="3+4"

Alain

Does it? Using your function I keep an assertion error. Storing the
return value of magic()in a variable s I receive the following result:

def magic(arg):
import inspect
return inspect.stack()[1][4][0].split("magic")[-1][1:-1]

s = magic(3+4) # magic line
'lin'


BTW grepping the stack will likely cause context sensitive results.

Kay
 
A

alainpoint

Kay said:
jalanb said:
You might like the version here:
http://www.jorendorff.com/toys/out.html

Especially the "need to know" presentation, which is cute

Thank you for the tip.
Meanwhile, I found a shorter solution to my problem:
def magic(arg):
import inspect
return inspect.stack()[1][4][0].split("magic")[-1][1:-1]

assert magic(3+4)=="3+4"

Alain

Does it? Using your function I keep an assertion error. Storing the
return value of magic()in a variable s I receive the following result:

def magic(arg):
import inspect
return inspect.stack()[1][4][0].split("magic")[-1][1:-1]

s = magic(3+4) # magic line
'lin'


BTW grepping the stack will likely cause context sensitive results.

Kay


This is no production-ready code, just a proof of concept.
Adding 3 or 4 lines would make it more robust.
Just hope someone else will benefit from this discussion.

Alain
 

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
474,290
Messages
2,571,453
Members
48,129
Latest member
DianneCarn

Latest Threads

Top