I am new to python and I know I can make the following code more concise using iteration (such as a for loop), I am just not sure how to
this is what I have so far
# Open file for reading
dataFileRead = open(filename, "r")
# Read file content into a list - to be completed - Part 1
SampleData = [line.rstrip('\n') for line in open(filename)]
print(SampleData)
variables = [mazeWidth, mazeHeight, aNumOfTreasures, aNumOfBombs, emptyCell, treasure, bomb, exitGate, boundary, boundarySide]
mazeWidth = SampleData[0]
mazeHeight = SampleData[1]
aNumOfTreasures = SampleData[2]
aNumOfBombs = SampleData[3]
emptyCell = SampleData[4]
treasure = SampleData[5]
bomb = SampleData[6]
mario = SampleData[7]
exitGate = SampleData[8]
boundary = SampleData[9]
boundarySide = SampleData[10]
any input helps! thank you
You can use a dictionary to hold the variables' names and values instead of having separate variables:
variable_names = ['mazeWidth', 'mazeHeight', 'aNumOfTreasures', 'aNumOfBombs', 'emptyCell', 'treasure', 'bomb', 'exitGate', 'boundary', 'boundarySide']
variables = {
name: SampleData[i] for i, name in enumerate(variable_names)
}
Later, if you want the value of the variable exitGate for example, you can use:
variables['exitGate']
And for assignment, use:
variables['exitGate'] = "some value"
If you want separate variables however, you can use this:
for i, name in enumerate(variable_names):
globals()[name] = SampleData[i]
And later you can access (get and set) the variables just as you normally would do (print(exitGate); exitGate = "some value").
If you really need these 11 variables to exist with their own names, abstain from any trick. 11 lines is no big deal.
Otherwise, keep working with the list SampleData.
If I were to use your method (which I wouldn't – I'll detail that later), I would edit your code as follows to combine SampleData with variables using zip() and dict().
# Open file for reading
dataFileRead = open(filename, "r")
# Read file content into a list - to be completed - Part 1
SampleData = [line.rstrip('\n') for line in open(filename)]
print(SampleData)
#previously known as variables
variable_names = ["mazeWidth", "mazeHeight", "aNumOfTreasures", "aNumOfBombs", "emptyCell", "treasure", "bomb", "exitGate", "boundary", "boundarySide"]
variables = dict(zip(variable_names, SampleData))
print(variables)
This will combine both lists into one dictionary. This way, if you want to access the number of bombs, or the width of the maze, all you have to do is write:
print(variables["aNumOfBombs"])
Dictionaries are useful like that. However, I would redo the system entirely. As your reading from a file anyway, I think you should make use of the json module and store the data that way. All of the code above would instead look like:
import json
with open(filename, "r") as var_file:
variables = json.load(var_file)
The only difference is how you structure the file you read from, which would instead look something like this:
{
"mazeWidth": 5,
"mazeHeight": 10,
"aNumOfTreasures": 4,
"aNumOfBombs": 16,
"emptyCell": "whatever",
"treasure": true,
"bomb": true,
"exitGate": false,
"boundary": "red",
"boundarySide": "NW"
}
Look into it!
Related
I'm relatively new to working in Python and can't quite figure this little problem out.
I have a function that takes a .txt file input and reads each line, and based on what is on that line, it will reference a dictionary to assign a variable name. That variable is then assigned a value (also from the .txt file). I've managed to set it up to successfully do this part, but I cannot get it to return those variables as a function output.
Here is a simplified example of what I have:
The .txt file looks something like this:
File Title: 'Test_Template.env' # filename
Number of Objects: 1 # Ns
Object Size: 20 # sd
And the function is something like:
def read_env_inputs(envFilename):
env_dict = {'File Title': 'filename',
'Number of Objects': 'Ns',
'Object Size': 'sd'}
with open(envFilename) as f:
lines = f.readlines()
for line in lines:
line = line.split(':')
if line[0] in env_dict.keys():
if line[0] == 'File Title':
vars()[env_dict[line[0]]] = line[1].split('#')[0].strip()
else:
if len(line[1].split('#')[0].split(',')) == 1:
vars()[env_dict[line[0]]] = float(line[1].split('#')[0].strip())
else:
vars()[env_dict[line[0]]] = list(map(float,line[1].split('#')[0].split(',')))
return filename Ns sd
If I run this as a script (not a function), I end up having the properly named variables in my workspace and can manipulate them. However, this does not successfully define them in a way that allows them to be an output of the function.
I'm trying to avoid creating an if/elif statement for each variable. I'd like it to be able to reference the dictionary based on the key (which is working) and use the value associated with that key as the variable name.
The main problem here is that you are accessing vars() which is the dictionary containing variables that are in scope and, therefore, you cannot return this. vars() something that is very rarely used and isn't the correct solution in this case.
Assuming that the txt file doesn't contain repeating lines you can do something like this:
def read_env_inputs(envFilename):
env_dict = {"File Title": "filename", "Number of Objects": "Ns", "Object Size": "sd"}
# Result dictionary
res = {}
with open(envFilename) as f:
lines = f.readlines()
# We already read the file and don't need to stay inside the with open block
# Going back one level in indentation closes the file
for line in lines:
line = line.split(":")
if line[0] in env_dict: # No need for .keys()
res_name = env_dict[line[0]] # Name it will have in the result dictionary
if line[0] == "File Title":
# No need for vars()
res[res_name] = line[1].split("#")[0].strip()
else:
if len(line[1].split("#")[0].split(",")) == 1:
# No need for vars()
res[res_name] = float(line[1].split("#")[0].strip())
else:
# No need for vars()
res[res_name] = list(map(float, line[1].split("#")[0].split(",")))
return res
You can call the function similar to this:
env = read_env_inputs(".env")
print(env["filename"])
If you really want to you can assign the result to variables like this (it shouldn't be necessary):
filename = env["filename"]
Ns = env["Ns"]
sd = env["sd"]
Or if you want to use vars() (not best practices):
for name, value in env.items():
vars()[name] = value
Btw this code still contains some duplication. everywhere you have line[1].split("#")[0] you can substitute this for a variable (similar to what is done to res_name).
I have some Python code that is generated dynamically and stored in a text file. It basically consists of various variables like lists and strings that store data. This information is fed to a class to instantiate different objects. How can I feed the data from the text files into the class?
Here is my class:
class SomethingA(Else):
def construct(self):
// feed_data_a_here
self.call_method()
class SomethingB(Else):
def construct(self):
// feed_data_b_here
self.call_method()
Here is some sample content from the text_a file. As you can see, this is some valid Python code that I need to feed directly into the object. The call the call_method() depends on this data for the output.
self.height = 12
self.id = 463934
self.name = 'object_a'
Is there any way to load this data into the class without manually copying and pasting all of its from the text file one by one?
Thanks.
I would probably write a parser for your files which would delete 'self.' at the beginning and add the variable to the dictionary:
import re
# You could use more apprpriate regex depending on expected var names
regex = 'self\.(?P<var_name>\D+\d*) = (?P<var_value>.*)'
attributes= dict()
with open(path) as file:
for line in file:
search = re.search(regex, line)
var_name = search.group(var_name)
var_value = search.group(var_value).strip() # remove accidentalwhite spaces
attributes[var_name] = var_value
foo = classA(**attributes)
example of the regex in work
Edit
If you use the code I've proposed, all items in the dictionary will be of the string type. Probably you can try:
eval(), as proposed by #Welgriv but with small modification:
eval(f'attributes[{var_name}] = {var_value}')
If your data consists of standard python data and properly formated you can try using json:
import json
x = '12'
y = '[1, 2, 3]'
z = '{"A": 50.0, "B": 60.0}'
attributes = {}
for i, v in enumerate([x, y, z]):
attributes[f'var{i+1}'] = json.loads(v)
print(attributes)
# Prints
# {'var1': 12, 'var2': [1, 2, 3], 'var3': {'A': 50.0, 'B': 60.0}}
You probably look for the eval() function. It evaluate and try to execute a python expression as text. For example:
eval('a = 3')
Will create a variable named a equal to 3. In your case you should open the text file and then evaluate it.
Remarks
eval() function present some security issues because the user can potentially execute any code.
I'm not sure what is the overall context of what you try to implement but you might prefer to store your data (name, id, height...) in another way than python code such as key-values or something because it will make your application extremely dependent of the environment. As an example, if there is a python update and some code are deprecated your application will not work anymore.
This is and example of what my csv file looks like with 6 columns:
0.0028,0.008,0.0014,0.008,0.0014,0.008,
I want to create 6 variables to use later in my program using these numbers as the values; however, the number of columns WILL vary depending on exactly which csv file I open.
If I were to do this manually and the number of columns was always 6, I would just create the variables like this:
thickness_0 = (row[0])
thickness_1 = (row[1])
thickness_2 = (row[2])
thickness_3 = (row[3])
thickness_4 = (row[4])
thickness_5 = (row[5])
Is there a way to create these variables with a for loop so that it is not necessary to know the number of columns? Meaning it will create the same number of variables as there are columns?
There are ways to do what you want, but this is considered very bad practice, you better never mix your source code with data.
If your code depends on dynamic data from "outer world", use dictionary (or list in your case) to access your data programatically.
You can use a dictionary
mydict = {}
with open('StackupThick.csv', 'r') as infile:
reader = csv.reader(infile, delimiter=',')
for idx, row in enumerate(reader):
key = "thickness_" + str(idx)
mydict[key] = row
Call your values like this:
print(mydict['thickness_3'])
From your question, I understand that your csv files have only one line with the comma separated values. If so, and if you are not fine with dictionares (as in #Mike C. answers) you can use globals() to add variables to the global namespace, which is a dict.
import csv
with open("yourfile.csv", "r", newline='') as yourfile:
rd = csv.reader(yourfile, delimiter=',')
row = next(rd)
for i, j in enumerate(row):
globals()['thickness_' + str(i)] = float(j)
Now you have whatever number of new variables called thickness_i where i is a number starting from 0.
Please be sure that all the values are in the first line of the csv file, as this code will ignore any lines beyond the first.
I have a file which looks like this :
OG_100000: V_bacterium_v|198260291 O_bacterium_v|391222558 O_terrae_v|182414991
and i did this function :
def readGroupFile(groupFileName):
dict_gene_taxonomy = {}
fh = open(groupFileName,"r")
for line in fh:
liste = line.split(": ")
groupName = liste[0]
genesAsString = liste[1]
dict_taxon = {}
liste_gene = genesAsString.split()
for item in liste_gene:
taxonomy_gene = item.split("|")
taxonomy = taxonomy_gene[0]
geneId = taxonomy_gene[1]
if taxonomy in dict_taxon:
listeCorrespondantATaxonomy = dict_taxon[taxonomy]
listeCorrespondantATaxonomy.append(geneId)
else:
dict_taxon[taxonomy] = []
dict_taxon[taxonomy].append(geneId)
dict_gene_taxonomy[groupName] = dict_taxon
fh.close()
return dict_gene_taxonomy
I did this function to make dictionaries and split element in each dictionary to be able to reach only the element after the pipe("|"), called geneId.
Then i made a function to create a Post Request on a internet database with these geneID. I'm not gonna link the whole function because it works properly when i manually add the geneId in the function's line :
data = urllib.parse.urlencode(getPost("391222558"))
considering the fact that "391222558" is one geneId from group file, but i need to replace these numbers by every "geneId" in my readGroupFile function.
i can't write :
data = urllib.parse.urlencode(getPost(geneId))
because i'm calling an element in a readGroupFile which is not defined outside this function.
So how can i reach all the "geneId" in my readGroupFile function to add this parameter in getPost(...) so it can work for every geneId in my group file ??
your problem is that you are creating only local variables , and those are deleted when the function end.
so you got couple of options:
the first one is define the geneid as a global variable , all you got to do is just:
global geneid
def readGroupfile():
global geneid
you will have to define him once not in a function and then whenever you use it just write global and his name,and it will make him global variable.
your secend options is to do the same with your dict , that also contain this variable.
i hope i helped you.
I have a large text file of lots of experimental results to search through for specific pieces of data, which I need to compile. The text file has results from many different experiments, and I need to keep the data from each experiment together.
e.g. (Not the actual data)
Object 1
The colour of the object is blue.
The size of the object is 0.5 m^3
The mass of the object is 0.8 g
Object 2
The colour of the object is pink.
The size of the object is 0.3m^3
etc.
I know where the values I want will be, as I can search the text for a specific phrase that I know will be present on the line the data is on.
One way I thought of doing it would be to search through the file for each specific line (I'm looking for two different variables), and add the value needed to a list. From this I would then create a dictionary for each object, assuming that at the same number in each list will be data from the same object.
e.g.
variable_one = []
variable_two = []
def get_data(file):
with open("filename.txt", "r") as file:
for line in file:
if "The colour" in line:
variable_one.append(line.split()[6])
if "The mass" in line:
variable_two.append(line.split()[6])
file.close()
or, to search through the file and create a list, with each entry being the section of data from a different object, then searching for the two variables for each object from within the different items in the list - again eventually storing the values from each object in a dictionary.
What I want to know is if there is a more efficient/better method for doing this than the ideas I had?
Here is an alternative which uses only one list and uses less "append" and less "in" and thus should be more effective.
variables = []
with open('filename.txt') as input:
colour = mass = ''
for line in input:
fields = line.split()
if len(fields)>6:
value = fields[6]
if 'The colour' in line:
colour = value
elif 'The mass' in line:
mass = value
elif line.startswith('Object'):
variables.append((colour, mass))
colour = mass = '' # may not be needed.
del(variables[0])
The way you are doing it there looks fine to me in general, except for the areas I mentioned in the comments, and the indexing causing an error if you have a line shorter than 6 words.