Turn ALL current workspace variables into global variables - excel

I have an aged code from different authors who use global variables over many years and the following challenge: I imported several (>200) variables from an excel file. They are not inside a function and they are not designated as global. For the function to work, they have to be because there is one function1 which calls a function 2. Function 1 is called once only while function 2 is called >10000 times, so I wish anything global to be inside function 1. How can I easily turn all of them into global variables and pass them to function 2?
example (scheme)
% function1
% global *other variables exist here already*
% this function calls function2 at a certain point further below
L=whos
save L % some variables a b c ... are parameters in function2
% function2
% global *other variables exist here already*
load L % i dont want to load my workspace everytime, I rather wish to just access global variables a b c...
% the problem is that my variables sometimes change name and I want to have
% them all global in an automatic way. Or live with a workaround.
Thank you for your patience and I am ready to take questions!
UPDATE I:
I managed a workaround with which im not entirely happy because it involves manual manipulation in the code. So it is a temporary solution at best.
% lets say you have some workspace variables and you save them under this name, and then load them:
load workspacevars.mat;
L=who % gives you those variable's names as string column
L=L' % and in a form that makes you able to use it as global (as row)
% unfortunately using global L doesnt work for me. any ideas?
% I had to go to L in the workspace, and click and drag the resulting long string into a text editor.
% there, I removed the braces {} and the '' because this is how global likes to have their variables: pure.
% finally it looks like this: global var1 var2 var3 ....

The answer is, use structure files instead of globals.
once the struct is created, (c.constant1, c.constant2...), you just give the function in question c. I used to work with workspace a lot, which explains why I save my workspace and load it once (not many times since constants dont change) so this is how it looks for me:
mainfunction
c.constant1=1;
save c.mat
[Time,Results] = ode15s(#(x, c) f1(x, c),[0 c.length],x0,options)
end
function [OUTPUT] = f1(t, x, c)
load c.mat
end
inputs are x and c and they can be freely shared between both the main and the subfunction. If constants should change due to some events in the function, they may be saved with an if conditions inside the subfunction and are reloaded in the next iteration of the code (but this is another issue adressed here: Change a constant in ODE calculations under particular conditions with a flag)

Related

Declaring variables inside a function python

For some reason I keep getting error in my code stating that my variables have not been declared. This only happens when I try to declare them in a function and not outside.
example
x, y = 105,107
print (x,y)
the above line of code works and gives me the output 105 107
but when I do this below
def fun1():
x, y = 105,107
print (x,y)
I get NameError: name 'x' is not defined
need help to understand what's happening.
One of the main utilities of functions is exactly the way they allow one
to isolate variables - no worries about clashing names for the code
in various functions - once a function works properly, it is done.
But if one needs to expose variables that populated inside functions to
the outside world, it is possible with the keyword "global". Notice that this
is in general considered bad practice, and even for small scripts,
there are often better solutions. But, common sense should always be the rule:
def fun1():
global x, y
x, y = 105, 107
fun1()
print(x, y)
Note that your code had another incorrect assumption: code
inside function bodies is not executed unless the function is called -
so, in the example in your question, even if you had declared
the variables as global, the print call would still
raise the same error, since you are not executing the line
that defines these variables by calling the function.
Now, you've learned about "globals" - next step is forget it
exists and learn how to work with variables properly encapsulated
inside functions, and when you get to some intermediate/advanced
level, then you will be able to judge when "globals" might actually
do more good than harm (which is almost never).

How a function in python can access the values which are declared outside its block and never passed as arguments during its call?

I have written a Python code in which a function without parameters can access the variable declared outside its scope. I want to know how Python interpreter can access this variable without giving any error like other programming languages(e.g. JAVA).
# Code 1:
def A():
# count accessed inside function
print(count)
# count declared outside function A
count = 23
A()
Output of code 1:
23
There is a bonus question also. In Python, if we declare any variable inside the loop then how it can used outside the loop. Because, as we know that the scope of any variable will remain under the block in which it is defined.
# Code 2:
for i in range(1):
# num declared inside for loop block
num = 23
# num can be accessed outside for loop block.
print(num)
Output of code 2: 23
Variable scope is inside-out. When you call a variable from inside a local scope like a function, first Python checks if there's a variable with that name in the local scope. If it doesn't find one, it expands the scope it checks in to the next outer scope. In your case, this is the global scope, the top-most level of scope. Declaring something absent of any context like a function or method defaults to the global scope, so that's where count lives.
If you want to be clear about which count it is you're referencing, you can add nonlocal count or global count to your function definition, making it explicit that you're referencing the a different scope.
Bonus question -- You can't reference a locally-scoped variable outside of its scope, so it doesn't work in reverse, sorry. However in your example you're using a loop, which does not have its own scope in Python (but Julia does, so if you ever make that switch heads up).

Calling functions with variables multiple times

I'm making a program for a school project and I'm having an issue.
I have defined a function called DidThisWork like so:
def DidThisWork():
global DidThisWork
DidThisWork = input('\n\nDid this solution work? - ').lower()
Throughout my code, I want to call this function multiple times, however, I'm not able to. Is there a way, to call it multiple times, and like reset the DidThisWork variable inside the function after I used it in if statements?
You define a function def DidThisWork(): then within that very function you overwrite the newly created DidThisWork variable (which points to the function) to the result of your input(..) call.
So at the first call to DidThisWork(), the DidThisWork variable no longer points to the function, rather to the string returned by input(...).
If you rename either the function or the variable storing the string returned by input() it should work.
By the way, there are some naming conventions in Python you may want to look into https://www.python.org/dev/peps/pep-0008/#id30. Typically you'd use snake_case instead of camelCase and not only start a class with an upper case letter
worked = None
def did_this_work():
global worked
worked = input('\n\nDid this solution work? - ').lower()
print(worked)
did_this_work()
print(worked)
did_this_work()
print(worked)

How to modify immutable objects passed as **arguments in functions with Python3 the elegant way?

I am not sure what the problem is here, so I don't really know how I should call the subject for that question. Please offer a better subject if you know.
The code below is a extrem simplified example of the original one. But it reproduce the problem very nice. After the call of test() foo should be sieben.
I think I didn't know some special things about scopes of variables in Python. This might be a very good problem to learn more about that. But I don't know on which Python topic I should focus here to find a solution for my own.
#!/usr/bin/env python3
def test(handlerFunction, **handlerArgs):
handlerFunction(**handlerArgs)
def myhandler(dat):
print('dat={}'.format(dat))
dat = 'sieben'
print('dat={}'.format(dat))
foo = 'foo'
test(myhandler, dat=foo)
print('foo={}'.format(foo))
Of course I could make foo a global variable. But that is not the goal. The goal is to carry this variable inside and through sub-functions of different levels and bring the result back. In the original code I use some more complexe data structures with **handlerArgs.
A solution could be to use a list() as an mutable object holding the immutable one. But is this really elegant or pythonic?
#!/usr/bin/env python3
def test(handlerFunction, **handlerArgs):
handlerFunction(**handlerArgs)
def myhandler(dat):
print('dat={}'.format(dat))
# MODIFIED LINE
dat[0] = 'sieben'
print('dat={}'.format(dat))
# MODIFIED LINE
foo = ['foo']
test(myhandler, dat=foo)
print('foo={}'.format(foo))
The ** syntax has nothing to do with this. dat is local to myhandler, and assigning it doesn't change the global variable with the same name. If you want to change the module variable from inside the function, declare the variable as global at the beginning of the function body:
def myhandler(): # you don't need to pass dat as argument
global dat
print('dat={}'.format(dat))
dat = 'sieben'
print('dat={}'.format(dat))
Here's a relevant portion from the docs:
If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block. This can lead to errors when a name is used within a block before it is bound. This rule is subtle. Python lacks declarations and allows name binding operations to occur anywhere within a code block. The local variables of a code block can be determined by scanning the entire text of the block for name binding operations.
If the global statement occurs within a block, all uses of the name specified in the statement refer to the binding of that name in the top-level namespace. Names are resolved in the top-level namespace by searching the global namespace, i.e. the namespace of the module containing the code block, and the builtins namespace, the namespace of the module builtins. The global namespace is searched first. If the name is not found there, the builtins namespace is searched. The global statement must precede all uses of the name.
After your edit the question reads as: "how do I mutate an immutable object?"
Well, I think you've guessed it: you don't. Using a mutable object in this manner seems reasonable to me.

How to return dynamically created vectors to the workspace?

Hello I'm trying to write a function which reads a certain type of spreadsheet and creates vectors dynamically from it's data then returns said vectors to the workspace.
My xlcs is structured by rows, in the first row there is a string which should become the name of the vector and the rest of the rows contain the numbers which make up the vector.
Here is my code:
function [ B ] = read_excel(filename)
%read_excel a function to read time series data from spreadsheet
% I get the contents of the first cell to know what to name the vector
[nr, name]=xlsread(filename, 'sheet1','A2:A2');
% Transform it to a string
name_str = char(name);
% Create a filename from it
varname=genvarname(name_str);
% Get the numbers which will make up the vector
A=xlsread(filename,'B2:CT2');
% Create the vector with the corect name and data
eval([varname '= A;']);
end
As far as I can tell the vector is created corectly, but I have no ideea how to return it to the workspace.
Preferably the solution should be able to return a indeterminate nr of vectors as this is just a prototype and I want the function to return a nr of vectors of the user's choice at once.
To be more precise, the vector varname is created I can use it in the script, if I add:
eval(['plot(',varname,')'])
it will plot the vector, but for my purposes I need the vector varname to be returned to the workspace to persist after the script is run.
I think you're looking for evalin:
evalin('base', [varname '= B;']);
(which will not work quite right as-is; but please read on)
However, I strongly advise against using it.
It is often a lot less error-prone, usually considered good practice and in fact very common to have predictable outcomes of functions.
From all sorts of perspectives it is very undesirable to have a function that manipulates data beyond its own scope (i.e., in another workspace than its own), let alone assign unpredictable data to unpredictable variable names. This is unnecessarily hard to debug, maintain, and is not very portible. Also, using this function inside other functions does not what someone who doesn't know your function would think it does.
Why not use smoething like a structure:
function B = read_excel(filename)
...
B.data = xlsread(filename,'B2:CT2');
B.name = genvarname(name_str);
end
Then you always have the same name as output (B) which contains the same data (B.data) and whose name you can also use to reference other things dynamically (i.e., A.(B.name)).
Because this is a function, you need to pass the variables you create to an output variable. I suggest you do it through a struct as you don't know how many variables you want to output upfront. So change the eval line to this:
% Create the vector with the correct name and data
eval(['B.' varname '= A;']);
Now you should have a struct called B that persists in the workspace after running the function with field names equal to your dynamically created variable names. Say for example one varname is X, you can now access it in your workspace as B.X.
But you should think very carefully about this code design, dynamically creating variables names is very unlikely to be the best way to go.
An alternative to evalin is the function assignin. It is less powerfull than evalin, but does exacty what you want - assign a variable in a workspace.
Usage:
assignin('base', 'var', val)

Resources