There are several problems with your approach, some coding errors, some conceptual.
The problem with the concept:
As I observed, the main issue is that you seem to think that putting some text into a file that is a comma-separated sequence of square-bracket enclosed comma-separated double-quoted text elements will create a list in your Python program when read using the file's handle with readlines()
.
What's more, when you complained about the single-quote enclosed string that was printed, it seems like you expected what you read from the file to be printed as separate square-bracket enclosed elements (perhaps each on a single line?), instead of a single string.
First, what you have in your text read from the file are not Python lists.
Python source code is only interpreted as source code, with statements and data like numbers, lists, tuples, etc. because they are read by the Python interpreter.
When you open()
a file and then call readlines()
on the file handle, it is not the Python interpreter that reads the file. Actually, at a low level, it is the kernel that reads the file in appropriately sized chunks and puts it into memory, namely into the piece of memory your allthequestions
variable refers to.
Think about it: if the first theory were true, then using readlines()
on a file would actually execute anything that looked like a Python command.
Then, how would it even know what to return? The result of the last expression, perhaps? A list of all expression results in the file? A tuple of them? No matter how we look at it, it would be hard to define what even your expected behavior for readlines()
is.
Things like this are best experimented upon in isolated, smaller examples, before putting them to use in a complete program.
Also, as its name suggests, readlines()
reads text as lines, not as comma-separated Python lists or any other tokens.
The result, although not a list, is an iterable collection of all lines in the file. This means that in your case - according to what you have written -, is a single line, containing:
["What would you wear to work?","Hoodie", "Suit", "Shorts","2"],["How would you greet a customer?","Hey", "Hi", "Hello", "0"],["How many years of experience do you have?","Loads", "None", "Some","1"],["Why do you want to work here?","It's fun", "No money", "Friend told me to","2"]
, including the newline at the end.
Inspecting this data structure, it seems like you want to parse a single sequence of sequences from a file, where each nested sequence contains text elements. The first (or in other words, 0th) element of each nested sequence is a question, whereas every other text element is a possible answer to that question.
What the number in the last element means, I could not decipher.
Solutions:
You could use a text parsing method called "regular expressions", but it might be too complicated for what you are trying to achieve.
Instead, what I'd suggest is to choose a different data structure.
If you'd only like to handle your data in Python, I'd suggest a method of serialization, like the pickle
module.
This module allows you to write a python object to a file in such a format that it can be read back again into a variable (of course, NOT with readlines()
, which is for reading lines, not objects).
To demonstrate how it works at the writing and reading end, here are some code snippets:
Example for the writing component:
# write_questions.py
import pickle
all_the_questions = (["What would you wear to work?","Hoodie", "Suit", "Shorts","2"],["How would you greet a customer?","Hey", "Hi", "Hello", "0"],["How many years of experience do you have?","Loads", "None", "Some","1"],["Why do you want to work here?","It's fun", "No money", "Friend told me to","2"])
questions_file = open("questions.dmp", "w")
pickle.dump(all_the_questions, questions_file)
questions_file.close()
Example for the reading component:
# read_questions.py
import pickle
questions_file = open("questions.dmp")
all_the_questions = pickle.load(questions_file)
print(all_the_questions[0])
print(all_the_questions[1])
The data structure of all_the_questions
was a tuple of lists of strings, which was dumped into the file "questions.dmp" using pickle.dump()
.
Note that the created file, "questions.dmp" contains a special object notation that is used by pickle
to read its contents back as a variable, and is not human-readable!
Once you've run the reading part, you'll see that indexing on the all_the_questions
variable worked properly after the variable was created from the file contents using pickle.load()
and you get something like this written to your terminal:
['What would you wear to work?', 'Hoodie', 'Suit', 'Shorts', '2']
['How would you greet a customer?', 'Hey', 'Hi', 'Hello', '0']
Another solution would be to use a standard textual data format, like CSV (comma separated values), for which there are parsers in the Python standard library.
Basically, you could store each question list as a separate line in a "questions.csv" file without delimiting it with []
characters, and each string could occupy a position between commas within the question line, like this:
What would you wear to work?,Hoodie, Suit, Shorts,2
How would you greet a customer?,Hey, Hi, Hello, 0
How many years of experience do you have?,Loads, None, Some,1
Why do you want to work here?,It's fun, No money, Friend told me to,2
The answer is already too long, so I leave it up to the reader interested in using CSV parsing to look up how it works. There are several resources available, just as for pickle.
The benefits are that the data, when stored in a file, will be human-readable, and handling it won't be restricted to Python programs, since CSV is a fairly often used, old format.
Coding issues:
The previous section already touched on the coding part with regards to readlines()
, but there are some more problems.
First:
forbuttons=[print(allthequestions)]
This line prints the text representation of the collection object stored in allthequestions
, converts the return value of print
into a list, and binds the resulting value to forbuttons
.
Since print()
always returns a value of None
, the value of forbuttons
will be a singleton list, only containing None
.
Printed, this would look something like this:
[None]
Next, the
textquestions.close
line does not actually call the close()
function on the file handle, it only evaluates the function object, doing nothing.
Then, the original snippet tries to call the object in forbuttons
with an argument of 0
as if it were a function. Alas, it is not, it is the list [None]
, as explained above:
q1 = forbuttons(0)
Afterwards, you suddenly decide to treat forbuttons
as an indexable list instead of a function, a multi-dimensional one at that!
buttonq1 = tk.Button(self, text=forbuttons[q1][0])
To be honest, I really have no idea what this would get you, so I can not propose an alternative either.
Maybe, what you wanted to do was something like:
buttonq1 = tk.Button(self, text=allthequestions[0][0])
, where the button's text would be set to the very first question, had you used e.g. pickle instead of readlines()
.
Another issue I find in your data representation is that you basically use magic numbers like 0
to remember where the actual question part of a question list is.
Maybe using a dictionary where the key is the actual question string, and the value the possible answers would be better. In that case, a single question structure would look like:
{ "What would you wear to work?" : ["Hoodie", "Suit", "Shorts","2"] }
The naming convention is also whacky for a couple of reasons:
First, it is ambiuous what is what. Is a "question" a whole data structure that includes the question string as it would be stated by a human, as well as the possible answers? Or is it just the question string?
Second: It does not look like variables in general follow any sane naming conventions. Usual naming conventions include "camelCase", "PascalCase" (or upper camel case), "snake_case", etc.
The Python style guide, PEP-8 recommends using "snake_case" for variables and functions, "UPPER_SNAKE_CASE" for variables intended to be constant and "PascalCase" for type names.
P.S.
In general, one should always learn and know what each concept, function, etc. is about / does before applying them, especially together.
This requires a lot of practice and experimentation, as well as learning from documentation.
To be honest, the original question does not look at all like much research or work was put into it.
Despite this, I have not disliked it, seeing that the original poster was a new contributor, and - as it seems - fairly new to programming as well.