Pass boolean argument by reference [duplicate] - python

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 9 months ago.
In C++ you can always pass something as reference and anything that happens within the callee would be known to caller by just examining the referenced variable.
Imagine this scenario:
def x():
a = f()
print(a)
def f():
return "hello"
What I want is add a boolean flag that returns from f to x. There are several ways to do that:
make f return a tuple (str,bool)
pass a reference to a boolean variable into f
option 1 is currently not possible since there are many callers to f() and I cant change them to accept tuple as return value, so it must stay as it is.
option 2 is not possible since boolean argument is immutable (as I've learned recently).
Only f can calculate the boolean value, and x needs to know about it.
Is there any good way to achieve that? Looking for something that is not bad practice in Python coding in general.

The option that's closest to passing a pointer/reference into f would be to pass it a mutable object, like a list:
def f(ok=None):
if isinstance(ok, list):
ok.append(True)
return "hello"
def x():
ok = []
a = f(ok)
print(a, ok.pop())
But the better solution IMO would be to return a tuple, and refactor that behavior into a new function so that you're sharing code without disturbing the existing API:
def f_with_flag():
return "hello", True
def f():
return f_with_flag()[0]
def x():
a, ok = f_with_flag()
print(a, ok)

Related

At what moment are closure cells evaluated? Can lambas have closures? [duplicate]

This question already has answers here:
What do lambda function closures capture?
(7 answers)
Closed last year.
Consider the following code:
def A():
l = list()
for i in range(5):
l.append(lambda: i)
return l
for f in A():
print( f() )
It prints out 4 five times, and I'm assuming it does that because the lambda function has taken the variable i through the outer scope of A, but right before the moment the variable became out of scope.
Then we have this code:
def B():
l = list()
for i in range(5):
l.append((lambda i: lambda: i)(i))
return l
for f in B():
print( f() )
It prints out all numbers from 0 to 4 in order. I am assuming it does that because the variable i has been grabbed from the scope of the outer lambda which took it as a parameter, so the value has been assigned to the cell in the moment when that external lambda finished executing.
But what if i held a mutable object instead of an immutable int?
def C():
l, i = list(), list()
for r in range(5):
i.append(r)
l.append((lambda i: lambda: i)(i.copy()))
return l
for f in C():
print( f() )
It does print out the lists in order as expected, because I used the list.copy() method in the argument.
Now, is my understanding correct?
If so, then is there a more pythonic or simpler way to save in a closure cell either an immutable object (or a copy of a mutable object), at the exact moment I want to? In other words, is there a better way than the (lambda i: lambda: i)(i) latch I came up with?
This happens because of late binding, try this code:
def bind(value):
return lambda: value
def A():
l = list()
for i in range(5):
l.append(bind(i))
return l
for f in A():
print( f() )
This way you can obtain the expected behaviour, since the binding is now on a value and not on a variable. Of course this is something tricky, and you should pay attemption to the behaviours of function like this, since python is using late binding.

How do you create new commands in Python when immutable data types are involved? [duplicate]

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 5 years ago.
In Python, the following code prints '0', not '1'.
def inc(x):
x = x+1
a = 0
inc(a)
print(a)
I understand why this happens; it's because integers are immutable. What I don't understand is how to get around this behaviour when it's undesirable. Suppose we want to create a new command such that the code
a = 0
inc(a)
print(a)
prints '1'.
Obviously, the naive approach won't do it. What can we do instead?
Similar (a bit more general) question can be found here along with a discussion how Python passes params to functions. In short, without making x variable in your code an object, I believe there's nothing we can do. Of course, you can alter your code to e.g. return changed value from function inc() and print that (i.e. print(inc(x))) or just do the printing from inside the inc() method, but that's not what you're essentially looking for.
If I understand correctly, You are trying to increment variable a using function inc(var) and passing 'a' as a external variable to the function inc().
As #Marko Andrijevic stated, variable x passed to function inc() and variable x defined in the function are different . One way to achieve is by returning value of x and collecting externally, which you may not be looking for.
Alternately, Since you have defined variable 'a' outside function ,it can be called global variable.
If you want to pass that to a function, and manipulate it, you need to define that variable ('a' in your case) inside the function as global. Something like below.
def inc(x):
global a
a = x+1
Now when the new value assigned to 'a' after 'x+1', it is retained after execution of 'inc(x)'
>>> a = 0
>>> inc(a)
>>> a
1
EDIT -1
As per comments by #DYZ . Its correct. declaring global a inside inc() function will always increment a.
A better alternative will be , in that case, to return x inside inc() and assign that value to any external variable.
Not an elegant solution, but works as intended.
def inc(x):
return x+1
Result
>>> a
0
>>> a = inc(a)
>>> a
1
>>> a = inc(a)
>>> a
2
>>> b = 0
>>> b = inc(b)
>>> b
1
>>> a
2
>>>
one can use yield to get variable values.
def inc(x,y,z):
x += 1
y+=1
z+=1
yield x,y,z #inc doesn't stop
yield x+y+z
a=b=c=0
gen=inc(a,b,c)
gen=list(gen)
a,b,c,sum=gen[0]+(gen[1],) #however, index must still be known
print a,b,c,sum

Send by ref/by ptr in python? [duplicate]

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 9 years ago.
i need help-i try to send value to method like in c++ by ref/by ptr
how can i do it?
to exmple:
def test(x):
x=3
x=2
test(x)
print(x)
In this case x a local variable in test method and will not change the "original" X
so how can i change the "original" X?
thanks
In some ways, all calls in Python are called with references. In fact, all variables are references in a sense. But some types, like int from your example, cannot be changed.
In the case of, say, a list, the functionality you're looking for is trivial:
def change_it(some_list):
some_list.append("world")
foo = ["hello"]
change_it(foo)
print(foo) # prints ['hello', 'world']
Note, however, that reassigning the parameter variable some_list does not change the value in the calling context.
If you're asking this question, though, you're probably looking to do something like set two or three variables using one function. In that case, you're looking for something like this:
def foo_bar(x, y, z):
return 2*x, 3*y, 4*z
x = 3
y = 4
z = 5
x, y, z = foo_bar(x, y, z)
print(y) # prints 12
Of course, you can do anything in Python, but that doesn't mean you should. In the fashion of the TV show Mythbusters, here's something that does what you're looking for
import inspect
def foo(bar):
frame = inspect.currentframe()
outer = inspect.getouterframes(frame)[1][0]
outer.f_locals[bar] = 2 * outer.f_locals[bar]
a = 15
foo("a")
print(a) # prints 30
or even worse:
import inspect
import re
def foo(bar):
# get the current call stack
my_stack = inspect.stack()
# get the outer frame object off of the stack
outer = my_stack[1][0]
# get the calling line of code; see the inspect module documentation
# only works if the call is not split across multiple lines of code
calling_line = my_stack[1][4][0]
# get this function's name
my_name = my_stack[0][3]
# do a regular expression search for the function call in traditional form
# and extract the name of the first parameter
m = re.search(my_name + "\s*\(\s*(\w+)\s*\)", calling_line)
if m:
# finally, set the variable in the outer context
outer.f_locals[m.group(1)] = 2 * outer.f_locals[m.group(1)]
else:
raise TypeError("Non-traditional function call. Why don't you just"
" give up on pass-by-reference already?")
# now this works like you would expect
a = 15
foo(a)
print(a)
# but then this doesn't work:
baz = foo_bar
baz(a) # raises TypeError
# and this *really*, disastrously doesn't work
a, b = 15, 20
foo_bar, baz = str, foo_bar
baz(b) and foo_bar(a)
print(a, b) # prints 30, 20
Please, please, please, don't do this. I only put it in here to inspire the reader to look into some of the more obscure parts of Python.
As far as I am aware, this doesn't exist in Python (although a similar thing occurs if you pass mutable objects to a function). You would do either
def test():
global x
x = 3
test()
or
def test(x):
return 3
x = test(x)
The second of these is much preferred.

Rewriting Python switch into a more compact way [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Replacements for switch statement in python?
Suppose I have a list in Python:
list = ('ADD', 'SUB', 'PUSH', 'POP')
I want to run a function depending on input, and that input can be any value in the list.
Instead of writing a switch case statement for each element in list, is there a more compact way of writing it?
My reasoning is for the case of the list growing in the future.
Well, there is no switch/case statement in Python.
For a small list, you want to use if/elif:
def do_stuff(x, *args):
if x == 'ADD':
return do_add(*args)
elif x == 'SUB':
return do_sub(*args)
# …
else:
raise RuntimeError('Never heard of {}'.format(x))
For a larger list, you want to make sure each case is a function (I already assumed that above, but if you had code like return args[0] + args[1], you'd have to change that into a do_add function), and create a dict mapping names to functions:
func_map = {'ADD': do_add, 'SUB': do_sub, … }
def do_stuff(x, *args):
try:
return func_map[x](*args)
except KeyError:
raise RuntimeError('Never heard of {}'.format(x))
This works because in Python, functions are normal objects that you can pass around like any other objects. So, you can store them in a dict, retrieve them from the dict, and still call them.
By the way, this is all explained in the FAQ, along with a bit of extra fanciness.
If you have some default function you'd like to call instead of raising an error, it's obvious how to do that with the if/elif/else chain, but how do you do it with the dict map? You could do it by putting the default function into the except block, but there's an easier way: just use the dict.get method:
def do_stuff(x, *args):
return func_map.get(x, do_default)(*args)
You could also use a pattern such as this (in a hurry so can't clean it up atm):
>>> class Test(object):
... def test_FOO(self):
... print 'foo'
...
... def test_BAR(self):
... print 'bar'
...
>>> def run_on(cls, name):
... getattr(cls, 'test_%s' % name)()
...
>>> run_on(Test(), 'FOO')
foo

How to get a closure to refer to the value that a variable had at the time of its definition [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Creating lambda inside a loop
In the code below, invoking any member of the returned array of closures
prints the number 4.
def go():
x = []
for i in range(5):
def y(): print i
x.append(y)
return x
I would like each member of the closure to print the number that i was when the closure was defined.
One way around this is to use default arguments:
def y(i=i):
print i
Default arguments are evaluated when the function is created, not called, so this works as you'd expect.
>>> i = 1
>>> def y(i=i): print i
...
>>> i = 2
>>> y()
1
A little extra info just for fun:
If you're curious what the defaults are, you can always inspect that with the .func_defaults attribute (__defaults__ in python3.x):
>>> y.func_defaults
(1,)
This attribute is also writeable, so you can in fact change the defaults after the function is created by putting a new tuple in there.

Categories

Resources