How to initilise a list that contains custom functions without python running those functions during initialisation? - python-3.x

Short version:
How do you store functions in a list and only have them be executed when they are called using their index position in the list?
Long Version:
So I am writing a program that rolls a user-chosen number of six-sided dice, stores the results in a list and then organizes the results/ data in a dictionary.
After the data is gathered the program gives the user options from 0-2 to choose from and asks the user to type a number corresponding to the option they want.
After this input by the user, a variable, lets say TT, is assigned to it. I want the program to use TT to identify which function to run that is contained within a list called "Executable_options" by using TT as the index posistion of this function within the list.
The problem I am having is that I have to have the list that contains the functions on a line after the functions have been defined and when I initialize the list it goes through and executes all functions within it in order when I don't want it to. I just want them to be in the list for calling at a later date.
I tried to initialise the list without any functions in and then append the functions individually, but every time a function is appened to the list it is also executed.
def results():
def Rolling_thunder():
def roll_again():
The functions contains things, but is unnecessary to show for the question at hand
Executable_options = []
Executable_options.append(results())
Executable_options.append(Rolling_thunder())
Executable_options.append(roll_again)
options = len(Executable_options)
I am relatively new to Python so I am still getting my head around it. I have tried searching for the answer to this on existing posts, but couldn't find anything so I assume I am just using the wrong key words in my search.
Thank you very much for taking the time to read this and for the answers provided.
Edit: Code now works

The () on the end of the function name calls it - i.e. results() is the call to the results method.
Simply append to the list without the call - i.e:
Executable_options.append(results)
You can then call it by doing e.g.:
Executable_options[0]()

as per your given data the code will look like this:
def results():
def Rolling_thunder():
def roll_again():
Executable_options = []
Executable_options.append(results)
Executable_options.append(Rolling_thunder)
Executable_options.append(roll_again)
for i in range(0,len(Executable_options)):
Executable_options[i]()
this will work for you.

Related

iterating over list in list; python

I have a simple problem. I'm new to python and programming so I think i miss something.
The variable "account_info" is assigned earlier and is a list of lists with 4 elements each. The variable current is a user input value, which (should) appear as the first element of the lists in the list account_info.
I want to iterate over the lists in the list and compare if the first element is equal to "current".
This is the code:
for i in account_info:
if current == account_info[i][0]:
email = account_info[i][1]
additional = account_info[i][2]
pw = account_info[i][3]
print(email)
I get an error in pycharm, when running that code. It seems that I can't iterate over the lists like that, can please someone explain and show a different solution?
Thank you
As #ForceBru commented, your issue is due to how for loops in Python work. The value you get from the loop is not an index into the iterable object you're looping on, rather, it's a value from the iterable. That makes your indexing with it later almost certainly wrong (though in certain contexts it might make sense, if you have a list that contains indexes into itself).
In your case, you probably want to do something more like this:
for account in accounts_info:
if current == account[0]: # note, only the inner indexing is needed
email = account[1]
additional = account[2]
pw = account[3]
Since you're expecting the inner lists to contain four values, you could even unpack the account values that you get from iterating directly into the inner variables. Though this would happen unconditionally, so it might not do what you want. Here's what that would look like, with the print call you were doing after the loop instead moved inside the conditional (so you only print the one email address that corresponds to the value in current):
for account_id, email, additional, pw in account_info: # unpack unconditionally
if account_id == current: # use the convenient name here
print(email) # print only in the conditional
In the rare case where you really do need to iterate over indexes, you can use the range type, which behaves like a sequence of integers (starting at zero by default). So you could replace your loop with this version and the body would work as you had intended (though this is less idiomatic Python than the previous versions).
for i in range(len(accounts_info)):
If you need both the index and the current value, you can use the enumerate function, which yields 2-tuples of index and value as you iterate over it. This is often handy when you need to reassign values in a list some times:
for i, account in enumerate(accounts_info):
if account[0] == current:
accounts_info[i] = new_value # replace the whole account entry

Method of sorted in python

The same code, run several times, but get the different results. Why the following results is not sorted?
You put your results into a dict – a data structure that does not guarantee any order of keys/values. It seems you're aware of that, judging by your call to sorted().
However, that function doesn't work as you presume: rather than modifying the list (or any iterable, in general), it returns a new one. Documentation linked above states:
Return a new sorted list from the items in iterable.
And since result of this function isn't assigned to any variable, it perishes. Alternately, result can be used directly as a collection to iterate over in a for loop, like this:
for key in sorted(scores):
print(scores[key] + ' had ' + key)

List to String to List Python 3

I need to convert a list into a string and then do the reverse process. Note that one script will convert List->String and another script will convert String->List, so store the list in a variable is not a solution. Use split(', ') or similar is not a solution either in all cases. So, as a challange I invite you to do the conversion in the following example:
l = ['ab,.cd\'ac"', b'\x80', '\r\nHi, !', b'\x01']
str_l = str(l)
I have tried one thing that worked: using exec() built-in function but people says is not a good practice, so I invite you to give me another alternative. Also I am having problems using exec() inside a function but that's another question that you can check -> Using exec() inside a function Python 3
This should work:
str_l = ("|").join(l)
Which gives you your first string. Then do:
l_2 = str_l.split("|")
Which gives you your second list.

Same for loop, giving out two different results using .write()

this is my first time asking a question so let me know if I am doing something wrong (post wise)
I am trying to create a function that writes into a .txt but i seem to get two very different results between calling it from within a module, and writing the same loop in the shell directly. The code is as follows:
def function(para1, para2): #para1 is a string that i am searching for within para2. para2 is a list of strings
with open("str" + para1 +".txt", 'a'. encoding = 'utf-8') as file:
#opens a file with certain naming convention
n = 0
for word in para2:
if word == para1:
file.write(para2[n-1]+'\n')
print(para2[n-1]) #intentionally included as part of debugging
n+=1
function("targetstr". targettext)
#target str is the phrase I am looking for, targettext is the tokenized text I am
#looking through. this is in the form of a list of strings, that is the output of
#another function, and has already been 'declared' as a variable
when I define this function in the shell, I get the correct words appearing. However, when i call this same function through a module(in the shell), nothing appears in the shell, and the text file shows a bunch of numbers (eg: 's93161), and no new lines.
I have even gone to the extent of including a print statement right after declaration of the function in the module, and commented everything but the print statement, and yet nothing appears in the shell when I call it. However, the numbers still appear in the text file.
I am guessing that there is a problem with how I have defined the parameters or how i cam inputting the parameters when I call the function.
As a reference, here is the desired output:
‘She
Ashley
there
Kitty
Coates
‘Let
let
that
PS: Sorry if this is not very clear as I have very limited knowledge on speaking python
I have found the solution to issue. Turns out that I need to close the shell and restart everything before the compiler recognizes the changes made to the function in the module. Thanks to those who took a look at the issue, and those who tried to help.

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