Pass python variable from object to parent - python

I'm writing a python program that wants to keep track of a status flag from several different places. I've done some reading to discover that a Python variable passed into a function can't necessarily be modified by that function (in my case it can't). As an example:
def testfunc(self, inVariable):
inVariable = 4
def main():
myVariable = 6
print myVariable
testfunc(myVariable)
print myVariable
In this situation, the output would be:
6
6
and the 4 would never be assigned to myVariable.
Realizing that this cannot be changed, does anyone have a good workaround for this situation? Global variables, perhaps?
The situation I am dealing with is much more complex than this one, so something like returning a value and assigning it is not an easy option for me.
Thanks!
Marlon

Three solutions:
pass it a collection object containing your data
def testFunc1(var):
var[0] = 4
myvar = [6]
testFunc1(myvar)
print(myvar[0])
make the variable a global
myvar = None
def testFunc2():
global myvar
myvar = 4
myvar = 6
testFunc2()
print(myvar)
I don't generally like global variables, but depending on what you're doing it may make sense.
return the variable from the function
def testFunc3(var):
return 4
myvar = 6
myvar = testFunc3(myvar)
print(myvar)
Edit: a fourth option; as per your declaration,
def testfunc(self, inVariable):
this appears to be a class method (passing self as an argument). If the status flag is a class variable or instance variable, the method can change it as self.status = 4 and this change will be retained.

Global variables, perhaps?
Global variables are almost always a bad idea.
A variable in Python is just binding a name to a value, in testFunc all you're doing is changing the value bound to inVariable rather than changing the variable itself.
You'll need to pass an object to your function and modify its attributes. You use a built-in type like list or dict, but it's just as easy to create your own class:
>>> class Status(object):
... # Lazily use a class variable as a default for instance variables
... flag = 0
...
>>> def testFunc(status):
... status.flag = 4
...
>>> s = Status()
>>> s.flag = 6
>>> s.flag
6
>>> testFunc(s)
>>> s.flag
4

Thanks everyone for the good ideas. I ended up "cheating" on this one: the program is written with Qt so I was able to use signals and slots to accomplish my goal.
Using class variables is an interesting idea; it sort of tricks python into creating a variable that is mutable, correct? I think global variables may have been a good way to go if not for my alternative solution; this seems like one of the rare cases where they may have been a good idea.
Hopefully these answers will help others with similar problems as well.
Cheers
Marlon

Related

How can I convert object attributes in mutable in Python? [duplicate]

How can I pass an integer by reference in Python?
I want to modify the value of a variable that I am passing to the function. I have read that everything in Python is pass by value, but there has to be an easy trick. For example, in Java you could pass the reference types of Integer, Long, etc.
How can I pass an integer into a function by reference?
What are the best practices?
It doesn't quite work that way in Python. Python passes references to objects. Inside your function you have an object -- You're free to mutate that object (if possible). However, integers are immutable. One workaround is to pass the integer in a container which can be mutated:
def change(x):
x[0] = 3
x = [1]
change(x)
print x
This is ugly/clumsy at best, but you're not going to do any better in Python. The reason is because in Python, assignment (=) takes whatever object is the result of the right hand side and binds it to whatever is on the left hand side *(or passes it to the appropriate function).
Understanding this, we can see why there is no way to change the value of an immutable object inside a function -- you can't change any of its attributes because it's immutable, and you can't just assign the "variable" a new value because then you're actually creating a new object (which is distinct from the old one) and giving it the name that the old object had in the local namespace.
Usually the workaround is to simply return the object that you want:
def multiply_by_2(x):
return 2*x
x = 1
x = multiply_by_2(x)
*In the first example case above, 3 actually gets passed to x.__setitem__.
Most cases where you would need to pass by reference are where you need to return more than one value back to the caller. A "best practice" is to use multiple return values, which is much easier to do in Python than in languages like Java.
Here's a simple example:
def RectToPolar(x, y):
r = (x ** 2 + y ** 2) ** 0.5
theta = math.atan2(y, x)
return r, theta # return 2 things at once
r, theta = RectToPolar(3, 4) # assign 2 things at once
Not exactly passing a value directly, but using it as if it was passed.
x = 7
def my_method():
nonlocal x
x += 1
my_method()
print(x) # 8
Caveats:
nonlocal was introduced in python 3
If the enclosing scope is the global one, use global instead of nonlocal.
Maybe it's not pythonic way, but you can do this
import ctypes
def incr(a):
a += 1
x = ctypes.c_int(1) # create c-var
incr(ctypes.ctypes.byref(x)) # passing by ref
Really, the best practice is to step back and ask whether you really need to do this. Why do you want to modify the value of a variable that you're passing in to the function?
If you need to do it for a quick hack, the quickest way is to pass a list holding the integer, and stick a [0] around every use of it, as mgilson's answer demonstrates.
If you need to do it for something more significant, write a class that has an int as an attribute, so you can just set it. Of course this forces you to come up with a good name for the class, and for the attribute—if you can't think of anything, go back and read the sentence again a few times, and then use the list.
More generally, if you're trying to port some Java idiom directly to Python, you're doing it wrong. Even when there is something directly corresponding (as with static/#staticmethod), you still don't want to use it in most Python programs just because you'd use it in Java.
Maybe slightly more self-documenting than the list-of-length-1 trick is the old empty type trick:
def inc_i(v):
v.i += 1
x = type('', (), {})()
x.i = 7
inc_i(x)
print(x.i)
A numpy single-element array is mutable and yet for most purposes, it can be evaluated as if it was a numerical python variable. Therefore, it's a more convenient by-reference number container than a single-element list.
import numpy as np
def triple_var_by_ref(x):
x[0]=x[0]*3
a=np.array([2])
triple_var_by_ref(a)
print(a+1)
output:
7
The correct answer, is to use a class and put the value inside the class, this lets you pass by reference exactly as you desire.
class Thing:
def __init__(self,a):
self.a = a
def dosomething(ref)
ref.a += 1
t = Thing(3)
dosomething(t)
print("T is now",t.a)
In Python, every value is a reference (a pointer to an object), just like non-primitives in Java. Also, like Java, Python only has pass by value. So, semantically, they are pretty much the same.
Since you mention Java in your question, I would like to see how you achieve what you want in Java. If you can show it in Java, I can show you how to do it exactly equivalently in Python.
class PassByReference:
def Change(self, var):
self.a = var
print(self.a)
s=PassByReference()
s.Change(5)
class Obj:
def __init__(self,a):
self.value = a
def sum(self, a):
self.value += a
a = Obj(1)
b = a
a.sum(1)
print(a.value, b.value)// 2 2
In Python, everything is passed by value, but if you want to modify some state, you can change the value of an integer inside a list or object that's passed to a method.
integers are immutable in python and once they are created we cannot change their value by using assignment operator to a variable we are making it to point to some other address not the previous address.
In python a function can return multiple values we can make use of it:
def swap(a,b):
return b,a
a,b=22,55
a,b=swap(a,b)
print(a,b)
To change the reference a variable is pointing to we can wrap immutable data types(int, long, float, complex, str, bytes, truple, frozenset) inside of mutable data types (bytearray, list, set, dict).
#var is an instance of dictionary type
def change(var,key,new_value):
var[key]=new_value
var =dict()
var['a']=33
change(var,'a',2625)
print(var['a'])

Python: importing a global variable into a local variable and then exporting into a global variable again

So I have something like this:
var1 = 6
var2 = 8
def somefunction(thing):
thing += 1
Now I want to make it so that somefunction(var1) actually makes var1 equal 7 globally. I looked around and I can't seem to find a good way to do this. Am I being thick? Sorry if this is obvious, I only started learning Python a couple days ago. Thanks.
#edit Ok, answered. Apparently it can't be done the way I wanted. Oh well.
Just have somefunction() return the new value:
def somefunction(thing):
return thing + 1
var1 = somefunction(var1)
You can't alter other references to a value; you pass in the value, not the name. thing is set to 6 in your example, not var1.
You could use a dictionary in place of a namespace, but you'll still need to pass in the name, not the variable:
namespace = {
'var1': 6,
'var2': 8,
}
def somefunction(thing):
namespace[thing] += 1
somefunction('var1')
Now we are naming what key in a global dictionary to alter, rather than passing in the value that that key references. You could do the same with the globals() dictionary, but then you run the risk of accidentally modifying globals outside of your constrained set of names you want to treat this way.
You may want to read the excellent Python Names and Values blogpost by Ned Batchelder in this context.
var1 = 6
def somef()
global var1
var1+= 1
There is no way in Python to reassign a variable in a caller from inside a called function.
var1 = 6
def cant_be_done(v):
v += 1
cant_be_done(var1)
assert var1 == 6
For more detail about why, see Python Names and Values

Python: How to make variables consistent throughout different functions?

I'm still starting out how to program in Python, and I'm just wondering how to make a variable consistent throughout different functions. For example, a function that I've made modified a variable. Then, I've used that variable again in another function. How can I make the modified variable appear in the 2nd function? When I try it, the 2nd function uses the original value of the variable. How can you make it use the modified value? Do I need to use global variables for this?
Also, is the input() function recommended to be used inside functions? are there any side effects of using it inside them?
The variables need to be shared by a scope that is common to both functions, but this need not necessarily be a global scope. You could, for instance, put them in a class:
class MyClass:
def __init__(self):
self.x = 10
def inc(self):
self.x += 1
def dec(self):
self.x -= 1
mc = MyClass()
print mc.x # 10
mc.inc()
print mc.x # 11
mc.dec()
print mc.x # 10
What scope exactly the variable should exist in depends on what you're trying to do, which isn't clear from your question.
Use global variabale to access variable throughout code.
Demo:
>>> a = 10
>>> def test():
... global a
... a = a + 2
...
>>> print a
10
>>> test()
>>> print a
12
>>>
In class, use class variable which is access to all instance of that class. OR use instance variable which is access to Only respective instance of the class.
You can use return in the function.
x = 3
def change1():
x = 5
return x
x = change1()
def change2():
print(x)
change1()
change2()
You can use the global keyword at the top of the function to let python know that you are trying to modify the variable in global score. Alternatively, you could use OOP and classes to maintain an instance variable throughout class functions.
x = 5
def modify():
global x
x = 3
modify()

How to make two functions share the same non global variable (Python)

Is there a way to make function B to be able to access a non global variable that was declared in only in function A, without return statements from function A.
As asked, the question:
Define two functions:
p: prints the value of a variable
q: increments the variable
such that
Initial value of the variable is 0. You can't define the variable in the global
enviroment.
Variable is not located in the global environment and the only way to change it is by invoking q().
The global enviroment should know only p() and q().
Tip: 1) In python, a function can return more than 1 value. 2) A function can be
assigned to a variable.
# Example:
>>> p()
0
>>> q()
>>> q()
>>> p()
2
The question says the global enviroment should know only p and q.
So, taking that literally, it could be done inline using a single function scope:
>>> p, q = (lambda x=[0]: (lambda: print(x[0]), lambda: x.__setitem__(0, x[0] + 1)))()
>>> p()
0
>>> q()
>>> q()
>>> p()
2
Using the tips provided as clues, it could be done something like this:
def make_p_and_q():
context = {'local_var': 0}
def p():
print('{}'.format(context['local_var']))
def q():
context['local_var'] += 1
return p, q
p, q = make_p_and_q()
p() # --> 0
q()
q()
p() # --> 2
The collection of things that functions can access is generally called its scope. One interpretation of your question is whether B can access a "local variable" of A; that is, one that is defined normally as
def A():
x = 1
The answer here is "not easily": Python lets you do a lot, but local variables are one of the things that are not meant to be accessed inside a function.
I suspect what your teacher is getting at is that A can modify things outside of its scope, in order to send information out without sending it through the return value. (Whether this is good coding practise is another matter.) For example, functions are themselves Python objects, and you can assign arbitrary properties to Python objects, so you can actually store values on the function object and read them from outside it.
def a():
a.key = "value"
a()
print a.key
Introspection and hacking with function objects
In fact, you can sort of get at the constant values defined in A by looking at the compiled Python object generated when you define a function. For example, in the example above, "value" is a constant, and constants are stored on the code object:
In [9]: a.func_code.co_consts
Out[9]: (None, 'value')
This is probably not what you meant.
Firstly, it's bad practise to do so. Such variables make debugging difficult and are easy to lose track of, especially in complex code.
Having said that, you can accomplish what you want by declaring a variable as global:
def funcA():
global foo
foo = 3
def funcB():
print foo # output is 3
That's one weird homework assignment; especially the tips make me suspect that you've misunderstood or left out something.
Anyway, here's a simpler solution than the accepted answer: Since calls to q increment the value of the variable, it must be a persistent ("static") variable of some sort. Store it somewhere other than the global namespace, and tell p about it. The obvious place to store it is as an attribute of q:
def q():
q.x += 1
q.x = 0 # Initialize
def p():
print(q.x)

Assigning a variable directly to a function in Python

Consider the following code:
def apples():
print(apples.applecount)
apples.applecount += 1
apples.applecount = 0
apples()
>>> 0
apples()
>>> 1
# etc
Is this a good idea, bad idea or should I just destroy myself?
If you're wondering why I would want this, I got a function repeating itself every 4 seconds, using win32com.client.Dispatch() it uses the windows COM to connect to an application. I think it's unnecessary to recreate that link every 4 seconds.
I could of course use a global variable, but I was wondering if this would be a valid method as well.
It would be more idiomatic to use an instance variable of a class to keep the count:
class Apples:
def __init__(self):
self._applecount = 0
def apples(self):
print(self._applecount)
self._applecount += 1
a = Apples()
a.apples() # prints 0
a.apples() # prints 1
If you need to reference just the function itself, without the a reference, you can do this:
a = Apples()
apples = a.apples
apples() # prints 0
apples() # prints 1
It is basically a namespaced global. Your function apples() is a global object, and attributes on that object are no less global.
It is only marginally better than a regular global variable; namespaces in general are a good idea, after all.

Categories