Python share variables between functions but not threads - python

I am writing some code that i have threaded, and am using various different functions at once. I have a variable called ref that is different for each thread.
ref is defined within a function within the threaded function, so when I use global ref, all the threads use the same value for ref (which I don't want). However when I don't use global ref, other functions can't use ref as it is not defined.
E.g.:
def threadedfunction():
def getref():
ref = [get some value of ref]
getref()
def useref():
print(ref)
useref()
threadedfunction()

If defining ref as global doesn't fit your needs then you don't have many other options...
Edit your function's parameters and returns. Possible solution:
def threadedfunction():
def getref():
ref = "Hello, World!"
return ref # Return the value of ref, so the rest of the world can know it
def useref(ref):
print(ref) # Print the parameter ref, whatever it is.
ref = getref() # Put in variable ref whatever function getref() returns
useref(ref) # Call function useref() with ref's value as parameter
threadedfunction()

Related

Python Class passing value to "self"

I'm programming an optimizer that has to run through several possible variations. The team wants to implement multithreading to get through those variants faster. This means I've had to put all my functions inside a thread-class. My problem is with my call of the wrapper function
class variant_thread(threading.Thread):
def __init__(self, name, variant, frequencies, fit_vals):
threading.Thread.__init__(self)
self.name = name
self.elementCount = variant
self.frequencies = frequencies
self.fit_vals = fit_vals
def run(self):
print("Running Variant:", self.elementCount) # display thread currently running
fitFunction = self.Wrapper_Function(self.elementCount)
self.popt, pcov, self.infoRes = curve_fit_my(fitFunction, self.frequencies, self.fit_vals)
def Optimize_Wrapper(self, frequencies, *params): # wrapper which returns values in manner which optimizer can work with
cut = int(len(frequencies)/2) <---- ERROR OCCURS HERE
freq = frequencies[:cut]
vals = (stuff happens here)
return (stuff in proper form for optimizer)
I've cut out as much as I could to simplify the example, and I hope you can understand what's going on. Essentially, after the thread is created it calls the optimizer. The optimizer sends the list of frequencies and the parameters it wants to change to the Optimize_Wrapper function.
The problem is that Optimize-Wrapper takes the frequencies-list and saves them to "self". This means that the "frequencies" variable becomes a single float value, as opposed to the list of floats it should be. Of course this throws an errorswhen I try to take len(frequencies). Keep in mind I also need to use self later in the function, so I can't just create a static method.
I've never had the problem that a class method saved any values to "self". I know it has to be declared explicitly in Python, but anything I've ever passed to the class method always skips "self" and saves to my declared variables. What's going on here?
Don't pass instance variables to methods. They are already accessible through self. And be careful about which variable is which. The first parameter to Wrapper_function is called "frequency", but you call it as self.Wrapper_Function(self.elementCount) - so you have a self.frequency and a frequency ... and they are different things. Very confusing!
class variant_thread(threading.Thread):
def __init__(self, name, variant, frequencies, fit_vals):
threading.Thread.__init__(self)
self.name = name
self.elementCount = variant
self.frequencies = frequencies
self.fit_vals = fit_vals
def run(self):
print("Running Variant:", self.elementCount) # display thread currently running
fitFunction = self.Wrapper_Function()
self.popt, pcov, self.infoRes = curve_fit_my(fitFunction, self.frequencies, self.fit_vals)
def Optimize_Wrapper(self): # wrapper which returns values in manner which optimizer can work with
cut = int(len(self.frequencies)/2) <---- ERROR OCCURS HERE
freq = self.frequencies[:cut]
vals = (stuff happens here)
return (stuff in proper form for optimizer)
You don't have to subclass Thread to run a thread. Its frequently easier to define a function and have Thread call that function. In your case, you may be able to put the variant processing in a function and use a thread pool to run them. This would save all the tedious handling of the thread object itself.
def run_variant(name, variant, frequencies, fit_vals):
cut = int(len(self.frequencies)/2) <---- ERROR OCCURS HERE
freq = self.frequencies[:cut]
vals = (stuff happens here)
proper_form = (stuff in proper form for optimizer)
return curve_fit_my(fitFunction, self.frequencies, self.fit_vals)
if __name__ == "__main__":
variants = (make the variants)
name = "name"
frequencies = (make the frequencies)
fit_vals = (make the fit_vals)
from multiprocessing.pool import ThreadPool
with ThreadPool() as pool:
for popt, pcov, infoRes in pool.starmap(run_variant,
((name, variant, frequencies, fit_vals) for variant in variants)):
# do the other work here

Python: Getting value from calling function

In Python, is there a simple way for an invoked function to get a value from the calling function/class ? I'm not sure if I'm phrasing that right, but I'm trying to do something like this:
class MainSection(object):
def function(self):
self.var = 47 # arbitrary variable
self.secondaryObject = secondClass() # Create object of second class
self.secondaryObject.secondFunction(3) # call function in that object
and
class secondClass(object):
def secondFunction(self, input)
output = input + self.var # calculate value based on function parameter AND variable from calling function
return output
#Access self.var from MainSection
This might be my lack of knowledge about Python, but I'm having a hard time finding a clear answer here. Is the best way to do that just passing the variable I want in as another second parameter to the second class?
These are in separate files, if that makes a difference.
Is the best way to do that just passing the variable I want in as another second parameter to the second class?
Yes, especially if there's only a transient relationship between the objects:
class secondClass(object):
def secondFunction(self, input, var_from_caller)
output = input + var_from_caller # calculate value based on function parameter AND variable from calling function
return output
You can even pass around the whole object if you like:
class secondClass(object):
def secondFunction(self, input, calling_object)
output = input + calling_object.var # calculate value based on function parameter AND variable from calling function
return output
If the relationship is more permanent, you could consider storing references to the related objects in instance variables:
class MainSection(object):
def function(self):
self.var = 47 # arbitrary variable
self.secondaryObject = secondClass(self) # Create object of second class
self.secondaryObject.secondFunction(3) # call function in that object
...
class secondClass(object):
def __init__(self, my_friend):
self.related_object = my_friend
def secondFunction(self, input)
output = input + self.related_object.var # calculate value based on function parameter AND variable from calling function
return output
#Access self.var from MainSection

How to write a function keeping return the maximum value while calling it repeatedly

I am learning Python and practice some problem on the book.
The problem asks me to write a function keeping the max value.
The function (foo) works like below:
if call foo(1) then print 1
call foo(5) print 5
call foo(3) print 5
call foo(10) print 10
call foo(8) print 10
I don't know what is the key point of this problem.
Another way (and much more correct in terms of encapsulation for the production code) to complete the task is to use classes instead of functions and global variables:
class MaxPositiveValue:
def __init__(self):
self.max_value = 0
def __call__(self, new_value):
'''
This magic method will emulate function call
:param new_value: new value to compare
:return: max value
'''
if new_value > self.max_value:
self.max_value = new_value
return self.max_value
foo = MaxPositiveValue()
print(foo(1)) # Will print "1"
print(foo(5)) # Will print "5"
print(foo(2)) # Will print "5"
print(foo(10)) # Will print "10"
print(foo(4.6)) # Will print "10"
print(foo(12.8)) # Will print "12.8"
And if you want to properly compare both positive and negative numbers, you may use next code:
class MaxValue:
def __init__(self):
self.max_value = None
def __call__(self, new_value):
'''
This magic method will emulate function call
:param new_value: new value to compare
:return: max value
'''
if (self.max_value is None) or (new_value > self.max_value):
self.max_value = new_value
return self.max_value
foo = MaxValue()
print(foo(-10.4)) # Will print "-10.4"
print(foo(-30.1)) # Will print "-10.4"
print(foo(1)) # Will print "1"
print(foo(5.6)) # Will print "5.6"
print(foo(2)) # Will print "5.6"
print(foo(10)) # Will print "10"
In mathematics, if a function is given certain input, it always returns the same value. That is what pure(sorry about being vague in wording) functions do. It means, your function will forget every information it used once it's done its job. In this case, your functions is not likely to remember previous max value and you will not be able to solve your problem, right? That's why other people suggested somewhat complex solutions like global variables or class. They do different jobs but they are all about keeping previous state(or what happened in the past). I would suggest one more method to achieve your goal. This may seem harder for now, but you will appreciate this later.
# written in Python3, not Python2
def function_factory():
prev_max = None
def print_max(num):
nonlocal prev_max
# prev_max is None or smaller than num
if not (prev_max and prev_max > num):
prev_max = num
print(prev_max)
return print_max
# make an instacne of print_max and bind that
# new function to the name, my_func
my_func = function_factory()
my_func(3) # >> 3
my_func(5) # >> 5
my_func(3) # >> 5
I used what's called a closure, and if you are interested you can study functional programming. It's a bit involved but makes your code succinct.
Your question is about global variables. It is saying to create a variable that is not dependent upon that instance of the function. Instance is used (in this case) to describe when that function is being used. Setting the variable as a global keeps it as that value irrespective of being in a different time the function has been called.
This code would be the solution:
glob_max = 0 #This variable needs to be set before the function
#(assuming you're just using natural numbers otherwise set a smaller number)
def foo(numbr):
if numbr > glob_max: #This find if it is the max or not
glob_max = numbr #Sets the variable
global glob_max #Makes the variable global to remember it for other functions
print(glob_max) #Print the number as required

How to create variables local to with statement?

I would like to create temporary variables visible in a limited scope.
It seems likely to me that you can do this with a "with" statement, and I would think there is a construct that makes it easy to do, but I cannot seem to find it.
I would like something like the following (but it does not work this way of course):
pronunciation = "E_0 g z #_1 m p l"
# ...
with pronunciation.split() as phonemes:
if len(phonemes) > 2 or phonemes[0].startswith('E'):
condition = 1
elif len(phonemes) < 3 and phonemes[-1] == '9r':
condition = 2
So is there a simple way to make this work, using built-ins?
Thanks!
Python creates local variables with function scope (once a name is used it stays alive until the end of the function).
If you really want to limit scope then "del <var>" when you want it explicitly discarded, or create separate function to act as a container for a more limited scope.
You can create a method
def process_pronunciation(pronunciation):
phonemes = pronunciation.split()
if len(phonemes) > 2 or phonemes[0].startswith('E'):
condition = 1
elif len(phonemes) < 3 and phonemes[-1] == '9r':
condition = 2
return condition
When you call the method, the local variable phonemes won't be available in the global namespace.
pronunciation = "E_0 g z #_1 m p l"
condition = process_phonemes(pronunciation)
You could do it with with, but I don't think it's worth the trouble. Basically (in a python function) you have two scopes - global or local, that's it. If you want a symbol to have a lifespan shorter than the function you'll have to delete it afterwards using del. You could define your own context manager to make this happen:
class TempVar:
def __init__(self, loc, name, val):
self.loc = loc
self.name = name
self.val
def __enter__(self):
if self.name in self.loc:
self.old = self.loc[self.name]
self.loc[self.name] = self.val
def __exit__(self, *exc):
if hasattr(self, "old"):
self.loc[self.name] = self.old
else:
del self.loc[self.name]
then you can use it to get a temporary variable:
with TempVar(locals(), "tempVar", 42):
print(tempVar)
The working is that it modifies the dict containing local variables (which is supplied to the constructor via locals()) on entry and restoring it when leaving. Please note that this relies on that modifying the result returned by locals() actually modifies the local namespace - the specification does NOT guarantee this behaviour.
Another (and safer) alternative that was pointed out is that you could define a separate function which would have it's own scope. Remember it's perfectly legal to nest functions. For example:
def outer():
def inner(tempVar):
# here tempVar is in scope
print(tempVar)
inner(tempVar = 42)
# here tempVar is out of scope
with statement does not have its own scope , it uses the surrounding scope (like if the with statement is directly inside the script , and not within any function, it uses global namespace , if the with statement is used inside a function, it uses the function's namespace(scope)).
If you want the statements inside a with block to run in its own local scope, one possible way would be to move the logic to a function , that way the logic would be running in its own scope (and not the surrounding scope of with.
Example -
def function_for_with(f):
#Do something.
with pronunciation.split() as phonemes:
function_for_with(phonemes)
Please note, the above will not stop phonemes from being defined in the surrounding scope.
If you want that as well (move the phonemes into its own scope), you can move the complete with statement inside a function. Example -
def function_with(pronunciation):
with pronunciation.split() as phonemes:
#do stuff
pronunciation = "E_0 g z #_1 m p l"
function_with(pronunciation)
Expanding on #skyking's answer, here's an even more magical implementation of the same idea that reads almost exactly like you wrote. Introducing: the with var statement!1
class var:
def __init__(self, value):
import inspect
self.scope = inspect.currentframe().f_back.f_locals
self.old_vars = set(self.scope.keys())
self.value = value
def __enter__(self):
return self.value
def __exit__(self, type, value, traceback):
for name in set(self.scope.keys()) - self.old_vars:
del self.scope[name]
### Usage:
line = 'a b c'
with var (line.split()) as words:
# Prints "['a', 'b', 'c']"
print(words)
# Causes a NameError
print(words)
It does all the nasty extracting of local variables and names for you! How swell. If you space it quirkily like I did and hide the definition in a from boring_stuff import * statement, you can even pretend var is a keyword to all of your confused co-workers.
[1] If you actually use this, the ghost of a dead parrot will probably haunt you forever. The other answers provide much saner solutions; this one is more of a joke.

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

Categories

Resources