python get current variables of the caller function - python

def foo():
a = 1
b = 2
dir() # prints [a, b]
bar(?)
der bar(foo_pointer):
print dir(foo_pointer) # should print [a,b]
I was trying to use
bar(sys.modules[__name__].main), but that gives not [a,b], but ['__call__','__class__' ...] without a and b.
I actually want to safe that pointer to use later, so i can't just pass the [a,b].

Use the sys._getframe() function to get access to the calling frame. Frame objects have a f_locals attribute giving you access to the local variables of that frame:
import sys
def bar():
caller = sys._getframe(1)
print caller.f_locals

Related

Can one function have multiple names?

I'm developing a bot on Python (2.7, 3.4). I defined a about 30+ dynamic functions which to be used based on bot commands. While development, since not all functions are done, I have to define for them an empty functions (if I not define then code won't run) like this:
def c_about():
return
def c_events():
return
def c_currentlocation():
return
etc. many dummy functions.
Question:
it is somehow possible in Python to define same function but with multiple names?
Something like this:
def c_about(), c_events(), c_currentlocation():
return
Yes, it's perfectly possible since defined functions are stored in variables like everything else.
def foo():
pass
baz = bar = foo
There is still some metadata relating to the original function (help(bar) will still mention foo), but it doesn't affect functionality.
Another option is to use lambdas for one-liners:
foo = bar = baz = lambda: None
Functions do not intern in Python (i.e., automatically share multiple references to the same immutable object), but can share the same name:
>>> def a(): pass
...
>>> a
<function a at 0x101c892a8>
>>> def b(): pass
...
>>> b
<function b at 0x101c89320>
>>> c=a
>>> c
<function a at 0x101c892a8> # note the physical address is the same as 'a'
So clearly you can do:
>>> c=d=e=f=g=a
>>> e
<function a at 0x101c892a8>
For the case of functions not yet defined, you can use a try/catch block by catching either a NameError:
def default():
print "default called"
try:
not_defined()
except NameError:
default()
Or use a dict of funcs and catch the KeyError:
funcs={"default": default}
try:
funcs['not_defined']()
except KeyError:
funcs['default']()
Or, you can do funcs.get(not_defined, default)() if you prefer that syntax with a dict of funcs.
Yes, it is possible, and it is even possible to store them in lists using loops. For instance:
l = []
for i in range(10):
l.append(lambda: None)
And you can reference any of them through indices like l[index]()
For example:
c_events = 0
c_about = 1
l[c_events]()

Python min override

In Python 3, I made a custom class C for a specific data structure that can be used as an iterable.
But the class ensures that for any data structure c of C, c[0] will be the minimum value of all values in c.
Is there a way that a call to min(c) simply returns c[0] without uselessly exploring all the structure ? (or as usual a ValueError if c is empty)
Is there a way that a call to min(c) simply returns c[0]?
Yes, there is 2 way :
The first one is modifying the source code of python and change the built in function structure, which is not wise and rational at all.
The second way is create your own min function in relative namespace.
Actually based on python name-resolution scheme which called the LEGB manner, When you use an unqualified name inside a scope, Python searches up to four scopes, the local (L) scope, then the local scopes of any enclosing (E) scopes (if it exist) , then the global (G) scope, and then the built-in (B) scope.Thus due to this rule the built in scope will be searches at end and you can simply create a new one on top level of this scope.
But Note that in that case you couldn't use the preceding min function, and if it happens to use it you can delete the costume function using del statement.
But another pythonic way to go with this task is that creating a min function inside your class and use it as an attribute :
>>> class C(object):
... def __init__(self):
... self.index = 0
... self.iterable = range(10)
... def __iter__(self):
... return self
... def min(self):
... try:
... return self.iterable[self.index]
... except IndxError:
... raise Exception('The index is out of range')
>>> c=C()
>>>
>>> c.min()
0
>>> c.iterable=[5,1,4,8]
>>> c.min()
5
Note that in this case you can specify a default index for min function to returns the relative item.

How to Access Function variables in Another Function [duplicate]

This question already has answers here:
How do I get a result (output) from a function? How can I use the result later?
(4 answers)
Closed 4 months ago.
I have a small issue while calling multiple variables in python one function to another. Like I have to access the variable of xxx() variables in yyy(). Help me to do this.?
Example :
def xxx():
a=10
b=15
c=20
def yyy():
xxx()
print a ### value a from xxx()
print b ### value b from xxx()
yyy()
Return them from your first function and accept them in your second function. Example -
def xxx():
a=10
b=15
c=20
return a,b
def yyy():
a,b = xxx()
print a ### value a from xxx()
print b ### value b from xxx()
yyy()
You can't. Variables created in a function are local to that function. So if you want function yyy to get the values of some variables defined in function xxx then you need to return them from xxx, as demonstrated in Sharon Dwilif K's answer. Note that the names of the variables in yyy are irrelevant; you could write:
def yyy():
p, q = xxx()
print p ### value a from xxx()
print q ### value b from xxx()
and it would give the same output.
Alternatively, you could create a custom class. Briefly, a class is a collection of data together with functions that operate on that data. Functions of a class are called methods, the data items are known as attributes. Each method of a class can have its own local variables, but it can also access the attributes of the class. Eg
class MyClass(object):
def xxx(self):
self.a = 10
self.b = 15
self.c = 20
def yyy(self):
self.xxx()
print self.a
print self.b
#Create an instance of the class
obj = MyClass()
obj.yyy()
output
10
15
Please see the linked documentation for more information about classes in Python.
Try this:
def xxx():
a=10
b=15
c=20
return a, b
def yyy():
a, b = xxx()
print a
print b
yyy()
Or this:
def xxx():
global a, b
a=10
b=15
c=20
def yyy():
print a
print b
xxx()
yyy()
For more info, use help('return') and help('global'), or see this and this question.
And only use global when you need the variable can use at everywhere or you need the function return other things. Because modifying globals will breaks modularity.
pickle.dump-workaround
In general, I'm working with a return statement if I need the variable for another function or a script.
But especially if I want to investigate why my code is failing with new data I'd like to analyze the parameters without rebuilding all the code.
My solution is just to store the file on disk.
def xxx():
a=10
tmp_dir = os.path.join(os.getcwd(),'tmp')
if not os.path.exists(tmp_dir):
os.mkdir(tmp_dir)
pickle.dump(a, open(os.path.join(tmp_dir,'a.pickle'), 'wb'))
b=15
c=20
Then you may load the parameter from where ever you want. In my case usually from a Jupyter-Notebook for the analyses.
def yyy():
a = pickle.load(open(os.path.join(tmp_dir,'a.pickle'), 'rb'))
print a ### value a from xxx()
print b
Btw: this is for sure a construction I would only use to analyze errors.
The answers people gave above are correct. But from a design perspective this is not something correct. Method local variables are mean to be local. If at all there is something that needs to be shared across a file or some set of methods I suggest you use file level variables or constants.
Use the global keyword, like the following example:
global a=0
global b=0
global c=0
def xxx():
a=10
b=15
c=20
return a,b
def yyy():
print a
print b
xxx()

Method Overriding?

I saw this particular piece of code:
def g(x,y):
return x+y
def g(x,y):
return x*y
x,y=6,7
print (g(x,y))
The output is obviously(but not to me) is 42. Can somebody please explain this behavior? This is method overriding I suppose, but I'm still not getting the flow here.
When you define a function, and you redefine it, it will use the last one you defined, even the parameter is different:
def g(x,y):
return x+y
def g(x,y):
return x*y
x,y=6,7
print (g(x,y))
def hello():
return 'hello'
def hello():
return 'bye'
print hello()
def withone(word):
return word
def withone():
return 1==1
print withone('ok')
Output:
42
bye
TypeError: withone() takes no arguments (1 given)
And function name in Python is more like simple variable:
def hello():
return 'hello'
iamhello = hello # bind to the old one
def hello():
return 'bye'
print hello() # here is the new guy
print iamhello()
OutPut:
bye
hello
The devil is in the order of function definitions.
This is not technically method overriding as that requires class inheritance, instead it's a result of how python declares and references functions.
When declaring a function, python stores a reference to that function in a variable named after the function definition. (e.g. variable would be "foo" for "def foo():")
By declaring the function twice, the value of that variable gets overwritten by the second definition.
A Python script is parsed from top till bottom.
So anytime the same name of a variable or function or class occurs, it overwrites any definitions that where associated with this name before.
def g(x,z):
print('first')
def g():
print('second')
g = 3
print g
print g()
So look at this example which will result in the printout of '3' and then in an Exception: 'TypeError: 'int' object is not callable'
The name g is at first a function with two parameters, then it gets redefined to be a function with no parameters, then it gets redefined to be an int.
Which cannot be called obviously :)
Everything in python is treated as object, whether it be a function name or class name. So, when we define a function using 'def', the memory allocation is done for that method. Then python points the name that we assign to the function, to this allocated memory location. So if we define a method :-
def demo():
print 'hi'
the memory is allocated for the method, and the name 'demo' is pointed to its memory location as follows :-
Now as described by zoosuck in his second example, when you assign the function name to another variable :-
demo2 = demo # bind to the old one
then in that case, the assigned memory location to demo, is assigned to demo2 as well. So both demo and demo2 points to same location 12506.
print id(demo) # will print 12506
print id(demo2) # will print 12506
Now if we modify the above piece of code and in the next line, define a new method with same name demo:-
def demo():
print 'hi'
demo2 = demo # bind to the old one
demo() # Will print hi
def demo():
print "hello"
demo() # Will print hello
demo2() # Will print hi
then a completely new memory location 12534 is allocated for this new method, and now demo will point to this new location 12534 instead of pointing to the old one i.e. to 12506. But demo2 is still pointing to the location 12506.
I hope this will give you a clear idea of what is going on and how the method name is over-written.
Order matters, if names are same,last function you defined is processing. In your case it's;
def g(x,y):
return x*y
g is just a variable. The fact that the object it refers to is a function doesn't make it special in Python, so you can assign and reassign it as you want. In this case, the second assignment (which is what a function definition is) simply replaces the object stored there with a different one.
Functions and methods are normal objects like any others. So in
def g(x, y):
return x + y
def g(x, y):
return x * y
the second object g will override(replace) the first one, just like object a does below:
a = 1
a = 2
The number, type or order of parameters does not make any difference, because Python does not support function/method override and does not allow two functions/methods to have the same name.
If you are familiar with lambda function, also often called anonymous\inline functions, this might clear things up a bit
These two code blocks are essentially equal
def g(x,y):
return x+y
def g(x,y):
return x*y
g = lambda x,y: x+y
g = lambda x,y: x*y

Do you change variables AFTER you run a function in python?

So I wrote this function from a book I am reading, and this is how it starts:
def cheese_and_crackers(cheese_count, boxes_of_crackers):
print "You have %d cheeses!" % cheese_count
print "You have %d boxes of crackers!" % boxes_of_crackers
print "Man that's enough for a party!"
print "Get a blanket.\n"
ok, makes sense. and then, this is when this function is run where I got a little confused and wanted to confirm something:
print "OR, we can use variables from our script:"
amount_of_cheese = 10
amount_of_crackers = 50
cheese_and_crackers(amount_of_cheese, amount_of_crackers)
the thing that confused me here is that the amount_of_cheese and amount_of_crackers is changing the variables (verbage? not sure if i am saying the right lingo) from cheese_count and boxes_of_crackers repectively from the first inital variable labels in the function.
so my question is, when you are using a different variable from the one that is used in the initial function you wrote, why would you change the name of the AFTER you wrote out the new variable names? how would the program know what the new variables are if it is shown after it?
i thought python reads programs top to bottom, or does it do it bottom to top?
does that make sense? i'm not sure how to explain it. thank you for any help. :)
(python 2.7)
I think you are just a bit confused on the naming rules for parameter passing.
Consider:
def foo(a, b):
print a
print b
and you can call foo as follows:
x = 1
y = 2
foo(x, y)
and you'll see:
1
2
The variable names of the arguments (a, b) in the function signature (1st line of function definition) do not have to agree with the actual variable names used when you invoke the function.
Think of it as this, when you call:
foo(x, y)
It's saying: "invoke the function foo; pass x in as a, pass y in as b". Furthermore, the arguments here are passed in as copies, so if you were to modify them inside the function, it won't change the values outside of the function, from where it was invoked. Consider the following:
def bar(a, b):
a = a + 1
b = b + 2
print a
x = 0
y = 0
bar(x, y)
print x
print y
and you'll see:
1
2
0
0
The script runs from top to bottom. The function executes when you call it, not when you define it.
I'd suggest trying to understand concepts like variables and function argument passing first.
def change(variable):
print variable
var1 = 1
change(var1)
In the above example, var1 is a variable in the main thread of execution.
When you call a function like change(), the scope changes. Variables you declared outside that function cease to exist so long as you're still in the function's scope. However, if you pass it an argument, such as var1, then you can use that value inside your function, by the name you give it in the function declaration: in this case, variable. But it is entirely separate from var! The value is the same, but it is a different variable!
Your question relates to function parameter transfer.
There are two types of parameter transfer into a function:
By value ------- value changed in function domain but not global domain
By reference ------- value changed in global domain
In python, non-atomic types are transferred by reference; atomic types (like string, integer) is transferred by value.
For example,
Case 1:
x = 20
def foo(x):
x+=10
foo()
print x // 20, rather than 30
Case 2:
d = {}
def foo(x): x['key']=20
foo(d)
print d // {'key': 20}

Categories

Resources