Thank you for the reply. Sadly I was due to my limited and short-time
knowledge of programming only able to understand 5-10% of your
explanation in only two days. Realistically speaking, I will maybe
understand your explanation fully in a month or two.
No worries.
Umm… is this any better? I am aware that the code does not work, however, I receive no syntax error.
No syntax errors just means that the code is “well formed”, like using
correct grammar in an English sentence. It doesn’t mean the code does
what you hoped to achieve.
Let’s step through your code:
word1 = input("Please give a word1: ")
word2 = input("Please give a word2: ")
This prompts the user and reads two responses into the variables word1
and word2
repsectively. All good.
mylist = ['word1', 'word2']
This makes a short list, containing the literal strings 'word1'
and
'word2'
. Those are not the strings the user entered. I suspect you
actually wanted:
mylist = [word1, word2]
This version uses the variables word1
and word2
, not the unrelated
strings 'word1'
and 'word2'
which are just… strings. Suppose the
user entered the words alpha
and beta
at your prompts. Then the
vairable word1
would refer to the string 'alpha'
, and the variable
word2
would refer to the string 'beta'
.
Your definition of the mylist
variable would make it refer to a list
witth these 2 strings:
'word1'
'word2'
Using the variables (eg word1
) instead of a literal string (eg 'word1'
)
makes a list with these 2 strings:
'alpha'
'beta'
because those are bound to the word1
and wod2
variables.
if mylist.sort() == ['word1', 'word2']:
Again, you’ve got literal strings instead of the variables. You want:
if mylist.sort() == [word1, word2]:
However, there’s a further complication.
The expression mylist.sort()
does not return a sorted version of
mylist
. Instead it sorts mylist
in place, and returns None
, the
Python placeholder value meaning “no value”. What you really want is:
if sorted(mylist) == [word1, word2]:
The sorted()
function makes a new list containing the values from
mylist
in sorted order and returns that new list. Let me demonstrate
interactively:
>>> L = [3, 2, 1]
>>> L
[3, 2, 1]
>>> sorted(L)
[1, 2, 3]
>>> L
[3, 2, 1]
>>> L.sort()
>>> L
[1, 2, 3]
Here we make a list of numbers, not sorted numericly. We show L
to
check that it has what we want. Then we show sorted(L)
, which makes a
new sorted list and returns it.
Then we show L
again, to see that it is unchanged (still not sorted).
The we call L.sort()
. This sorts the list in place i.e. it modifies
L
itself. And returns None
. You can tell it returned None
because
the value of L
was not printed.
Then we show L
again, and see that it is sorted.
This convention is common in Python: functions which modify something in
place like L.sort()
return nothing, and functions which create a new
thing like sorted(L)
return the new thing. This avoids some common
mistakes.
Note that they “avoid” these mistakes by returning None
, which is not
useful. It doesn’t means that they don’t run! It just means that your
code won’t work correctly with the L.sort()
form.
That is why you actually want this test:
if sorted(L) == [word1, word2]:
The same issues apply to your elif
test.
Let’s look at your substring check:
"z" in "str(word1)" and "z" in "str(word2)"
if False:
print("Neither word has 'z' in it.")
else:
print("Something went wrong.")
Usually, evaluating an expression without using its result, such as
assigning it to something, is not useful. So this:
"z" in "str(word1)" and "z" in "str(word2)"
performs a test but does not store the result of the test anywhere.
Typically you’d put this test directly into the if-statement so that the
if-statement gets to use the result, eg:
if "z" in "str(word1)" and "z" in "str(word2)":
........
Alternatively you can store the result in a variable:
z_in_both = "z" in "str(word1)" and "z" in "str(word2)"
and then use the variable in the if-statement:
if z_in_both:
........
But there are problems with the test itself, and they’re a lot like the
problems you had with mylist
earlier. This:
"str(word1)"
is a literal string, representing the text:
str(word1)
So you’re seeing if the string "z"
occurs in the string "str(word1)"
(which it does not, so the test will always return False
). I think
what you really intended is written like this:
z_in_both = "z" in word1 and "z" in word2
which looks for "z"
in the string referred to by word1
. In my
example input, that would be a string containing this text:
alpha
Likewise for word2
.
In Python, text between quotes is a literal piece of text. A word not
in quotes is a variable name, and the value used is what it referes to.
Here’s an interactive example:
>>> w = "text1"
>>> y = "w"
>>> y
'w'
>>> y = w
>>> y
'text1'
Here we make a string "text1"
. And refer to it with the variable w
.
Using y = "w"
assigns the literal string "w"
to y
.
Using y = w
assigns the string referred to by the variable w
to y
.
Coming back to the if-statement after your "z"
test:
if False:
print("Neither word has 'z' in it.")
else:
print("Something went wrong.")
This tests the value False
, which is always false! So it will always
run the second print()
call.
What you actually want to test it the result of your test. So this will
work:
z_in_both = "z" in word1 and "z" in word2
if z_in_both:
print("Something went wrong.")
else:
print("Neither word has 'z' in it.")
Notice that I switches the print()
s to match the result of the test.
However, this print()
is not saying the right thing:
print("Neither word has 'z' in it.")
This is because z_in_both
will only be true if both words contain a
"z"
. So a false result doesn;t mean that neither contains a "z"
;
it is enough for just one to not contain "z"
for the result to be
false (because you used and
to combine the individual tests). So the
print()
should say:
print("At least one of the words does not contain 'z'.")
or something equivalent to that.
Continuing:
tested_word = input("Please give a word to test: ")
palindrome = tested_word [(len(tested_word))::-1]
Ok, so you’re getting the reversed form of tested_word
using a funky
slice which has a negative step (the -1
).
if str(tested_word) == str(palindrome):
print("The word you gave is a palindrome.")
This is correct. But both tested_word
and palindrome
are already
strings. You you can just write:
if tested_word == palindrome:
print("The word you gave is a palindrome.")
which is much easier to read.
elif str(tested_word) != str(palindrome):
print("The word you gave is no palindrome.")
Technically, you do not need the !=
test. If your code runs the
elif...else...
section then you already know that
tested_word!=palindrome
because the ==
test failed. So you could
simplify this down to:
else:
print("The word you gave is no palindrome.")
However, I want to commend you for the final else:
anyway. We often
write an if
/elif
/elif
/…/else
chain to sort out various
circumstances, and I commonly see the else:
part left out because the
programmer thinks that the conditions in the if
and elif
should
cover everything which can happen. But circumstances can change, and it
is prudent to always catch the “none of the above” situation and log
an error or raise an exception.
Here’s a real world example from my own code:
if opt == '-d':
if not isdirpath(val):
raise GetoptError("not a directory: %r" % (val,))
options.spdpath = val
elif opt == '-n':
options.doit = False
else:
raise RuntimeError("unhandled pre-option")
Here I’m handling some command line switches: -d
and -n
.
In theory the else:
part of this code can never run because the code
which defines opt
only recognises -d
or -n
, and so opt can only
ever be one of those two and in a perfect world the last else:
can
never happen.
However, supposing I modify the earlier stuff which sets opt
to
recognise some additional option, but forget to update this
if-statement above? Without the else:
part it would quietly ignore
whatever extra option that was. With the else:
it explodes loudly,
making it obvious that there’s a gap in my logic.
It is almost always good to have a catch-all at the end.
Finally, the last print()
call:
print("It is reversed '", "", str(tested_word [len(tested_word)::-1]), "", "' and corretly", " ", str(tested_word), sep="")
First: you don’t need str(tested_word)
etc. These things are already
strings.
Second: if you want to get these strings with quotes around them (to
make the output more understandable) Python has a handy function named
repr()
which ideally returns a string which is a Pythin expression for
the value you hand it. So:
print(word1)
might print the text:
alpha
but this:
print( repr(word1) )
would print the text:
'alpha'
which is the Python expression for that literal string value. The you
could go:
print("It is reversed", repr(tested_word [len(tested_word)::-1]), "and correctly", repr(tested_word))
to get readable output.
Cheers,
Cameron Simpson cs@cskk.id.au