Python extracting body from function at runtime - python

Given a function in Python defined as follows:
a = 3
b = 4
c = 5
def add():
d = a+b+c
is it possible to get a code object or similar that gives me:
a = 3
b = 4
c = 5
d = a+b+c

The function object has a code object associated with it; you can exec that code object:
>>> a = 3
>>> b = 4
>>> c = 5
>>> def add():
... d = a+b+c
...
>>> exec add.func_code
This will not however set d in the local namespace, because it is compiled to create a local name only, using the STORE_FAST opcode. You'd have to transform this bytecode to use STORE_DEREF opcodes instead, requiring you to learn AST transformations.
If you did want to go down this route, then read Exploring Dynamic Scoping in Python, which teaches you the ins and outs of Python scoping and byte code.

You can use the global command, which
is the most simple way in my opinion
>>> a = 3
>>> b = 4
>>> c = 5
>>> def add():
global d
... d = a+b+c

Related

Replace variable of a function while calling it in python?

Sorry for my bad english.
Is there any way to replace variable of a method from outside?
Suppose i have two files app.py and try.py.
In app -
def call():
c=5
return c
In try -
from app import *
c=1000
d=call()
print(d)
When i run try, here i want the output to be 1000 not 6. Is there any way to do this ?
I don't know any way to change c dynamically. Python compiles c = 5 into a LOAD_CONST op code as seen in the disassembly. And changing that op code would require, um, .... I don't know.
>>> from dis import dis
>>> def call():
... c=5
... return c
...
>>> dis(call)
2 0 LOAD_CONST 1 (5)
2 STORE_FAST 0 (c)
3 4 LOAD_FAST 0 (c)
6 RETURN_VALUE
You can monkey patch, though. Write your own implemenation of call and assign it dynamically at the start of your program.
import app
# from app, a reimplementation of call
def my_app_call_impl(c=1000):
return c
app.call = my_app_call_impl
add c argument to the function and use it like that
app file
def call(c):
return c
The second file
from app import *
c = 1000
d = call(c)
print(d)
if you want to c have a default value then app file should look like this
def call(c = 5):
You can define parameters for the call function:
app.py:
def call(c): # one parameter, c
return c
try.py
from app import *
c = 1000
d = call(c) # function called with c as an argument
print(d) # 1000
You can also use 5 as a default:
app.py
def call(c = 5):
return c
try.py
from app import *
d = call()
print(d) # 5
Functions in Python
*in app.py : *
def call(c=5):
return c
*in try.py : *
from app import *
d=call(1000)
print(d)

Functions aren't running

My functions in Python aren't returning values that I expect them to. Here is a MWE:
a = 6
b = 18
c = 0
def random_function(c):
c = b/a
return c
random_function(c)
print(c)
I expect this function to print 3, but instead it prints 0. I have just updated from 2.7 to 3.6 and this would have worked in 2.7 - what am I doing wrong?
Need to store returned value from method.
a = 6
b = 18
c = 0
def random_function(c):
c = b/a
return c
c= random_function(c)
print(c)
As #Dharmesh said, you need to store the value of c when it comes out of random_function().
i.e. c = random_function(c)
The Reason:
Scope is everything. When you change the value of c from within the function, it only affects the value of c within the scope of that function and doesn't change its value in the global context.
In order for the value you assigned to c from within the function to be preserved, you need to assign c the value returned by the function.
you are printing c value which was assigned globally.
a = 6
b = 18
c = 0
def random_function(c):
c = b/a
return c # -- this variable scope is local
random_function(c)
print(c) #-- prints Global variable
to print as you expected, you need to change your function call like below
print (random_function(c))
or
c = random_function(c) # this will re assign global value of 'c' with function return value
print(c)

Python scoping in functions

Consider the following code:
>>> b = 3
>>> def change (b):
... b = 2
...
>>> change(b)
>>> print(b)
3
I am not confused by the fact that the print statement returns 3. Here's the question: is this because of scope, or because the argument that the function takes is not related to the outside b?
The b inside change is of a different scope than b outside of change. Inside the scope of the function, it does not matter what you call the variable before you pass it in - for now, it's going to be called b. As long as you don't return b from change and assign it to your "original" b, the first one won't change.
def change(b):
b = 2
return b
change(b)
print(b) # 3
b = change(b)
print(b) # 2
You are reassigning b. It does not change the parameter. You can test this using the id() function before and after the assignement.
The scope answers are partially correct for the object type you are passing.
Check out this link for information about how python "passes by value reference"
http://stupidpythonideas.blogspot.com/2013/11/does-python-pass-by-value-or-by.html
Here is another link that explains pythons Local -> Enclosed -> Global -> Built-in scope resolution with some examples:
http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/not_so_obvious_python_stuff.ipynb#python_legb
FWIW, the behavior is slightly different if we consider mutable objects:
>>> b = [3]
>>> def change(b):
... b[0] = 2
...
>>> change(b)
>>> print(b)
[2]
>>>
You have asked quite a tricky question, in the sense that the terminology you have used in framing the question is making people give you differing and weird answers.
You've given two choices:
we have a scope issue
b inside the function isn't related to b outside the function
Well, they are both true, and they are really just two ways to say the same thing.
Forgetting about terminology for a moment, realize that there is absolutely no difference between
b = 3
def f(a):
print(a)
f(b)
and
b = 3
def f(b):
print(b)
f(b)
The parameter names in a function's signature (the def line of a function) are local to the function, no matter what names are outside the function.
Now, you probably noticed that I sidestepped the issue of assignment within a function. That's because it's harder to explain quickly, but still be understandable and memorable to someone still in the fairly early stages of learning Python (which, no offense, it seems like you are).
Here is some reading that should help you understand fundamental concepts in Python:
http://nedbatchelder.com/text/names.html
http://www.jeffknupp.com/blog/2013/02/14/drastically-improve-your-python-understanding-pythons-execution-model/
You need to look at global variables. Just add global b at the beginning of your code and function, and it should work:
>>> global b
>>> b = 3
>>> def change():
... global b
... b = 2
...
>>> b
3
>>> change()
>>> b
2
>>>
You also need to remove the b parameter from def change(b), because that makes b both local and global. You can also return b:
>>> b = 3
>>> def change(b):
... b = 2
... return b
...
>>> b
3
>>> b = change(b)
>>> b
2
It is a scoping problem. b in the function is a local variable.
globals() is dictionary which hold all global variables.
b=3
def change (a):
globals()[a] = 2
print b
# 3
change("b")
print b
# 2

Python getting a variable to change as what it's assigned to changes [duplicate]

This question already has answers here:
How to create recalculating variables in Python
(8 answers)
Closed 9 years ago.
For example, if I say:
a = 50
b = 3 * a
a = 46
The value of b after this runs would still be 3 * 50 = 150. How would I assign b to equal 3 * a such that when a changes, the value of b also changes, without me having to restate b = 3 * a again?
EDIT: I would have searched this up but I really wasn't sure how to word it.
With lambda function
You can create a lambda function. But, it requires you to add empty parenthesis after each call of b.
>>> a = 50
>>> b = lambda: a * 3
>>> b
<function <lambda> at 0xffedb304>
>>> b()
150
>>> a = 45
>>> b()
135
EDIT: I have already respond at this kind of anwser here: How to create recalculating variables in Python
With a homemade class
Another way given on this same thread is to create an Expression class, and change the repr return.
Fair warning: this is a hack only suitable for experimentation and play in a Python interpreter environment. Do not feed untrusted input into this code.
class Expression(object):
def __init__(self, expression):
self.expression = expression
def __repr__(self):
return repr(eval(self.expression))
def __str__(self):
return str(eval(self.expression))
>>> a = 5
>>> b = Expression('a + 5')
>>> b
10
>>> a = 20
>>> b
25
Make b into a function:
def b():
return 3 * a
then use it by calling it, i.e. b()
What do you thing of this way ? :
class XB(object):
def __getattribute__(self, name):
try:
return 3 * a
except:
return None
x = XB()
print 'x.b ==',x.b
a = 50
print 'x.b ==',x.b
a = 46
print 'x.b ==',x.b
return
x.b == None
x.b == 150
x.b == 138

Is there a Pythonic way to close over a loop variable?

I just ran across Eric Lippert's Closing over the loop variable considered harmful via SO, and, after experimenting, realized that the same problem exists (and is even harder to get around) in Python.
>>> l = []
>>> for r in range(10):
... def foo():
... return r
... l.append(foo)
...
>>> for f in l:
... f()
...
9
9
9
# etc
and, the standard C# workaround doesn't work (I assume because of the nature of references in Python)
>>> l = []
>>> for r in range(10):
... r2 = r
... def foo():
... return r2
... l.append(foo)
...
>>> for f in l:
... f()
...
9
9
9
# etc
I recognize that this isn't much of a problem in Python with its general emphasis on non-closure object structures, but I'm curious if there is an obvious Pythonic way to handle this, or do we have to go the JS route of nested function calls to create actually new vars?
>>> l = []
>>> for r in range(10):
... l.append((lambda x: lambda: x)(r))
...
>>> for f in l:
... f()
...
0
1
2
# etc
One way is to use a parameter with default value:
l = []
for r in range(10):
def foo(r = r):
return r
l.append(foo)
for f in l:
print(f())
yields
0
1
2
3
4
5
6
7
8
9
This works because it defines an r in foo's local scope, and binds the default value to it at the time foo is defined.
Another way is to use a function factory:
l = []
for r in range(10):
def make_foo(r):
def foo():
return r
return foo
l.append(make_foo(r))
for f in l:
print(f())
This works because it defines r in make_foo's local scope, and binds a value to it when make_foo(r) is called. Later, when f() is called, r is looked-up using the LEGB rule. Although r is not found in the local scope of foo, it is found in the enclosing scope of make_foo.

Categories