Python: Loop through the elif section of an if statement - python

I'm relatively new to python, so I'm not even sure if I'm approaching this in the correct way. But I haven't found a good solution anywhere.
In order to avoid very ugly and repetitive code, i want to loop the elif part of the if statement.
This is the ugly code i want to fix:
def codeToChar(code):
chars = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"
if code == ord(chars[0]): ##### SUPER UGLY
return chars[0]
elif code == ord(chars[1]):
return chars[1]
elif code == ord(chars[2]):
return chars[2]
elif code == ord(chars[3]):
return chars[3]
elif code == ord(chars[4]):
return chars[4]
elif code == ord(chars[5]):
return chars[5]
..... etc .....
else:
return "wat"
As you can see, the index is incrementing by one, so I thought looping would be very simple. However, when I tried the following, it didn't work because this must be formulated as an if, elif, elif, else statement, and not many if statements.
My failed attempt:
for x in xrange(0,len(chars)-1):
if code == ord(chars[x]):
return chars[x]
else:
return "wat"
How would I go about looping this?
Note: if it's of any relevance, I'm coding this using the curses module, building a keyboard interface for a project.
Many thanks

for c in chars:
if code == ord(c):
return c
return "wat"
the second return is executed only if no previous return has been previously executed (i.e. no character matched).

It seems like you are just checking whether the code is one of the characters or not. One clean solution would be:
c = chr(code)
return c if c in chars else "wat"

Use a dict:
chars = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"
chars_dict = {ord(c): c for c in chars}
return chars_dict.get(code, 'wat')

You don't want to return "wat" inside the loop as it'll trigger as soon as the if statement fails once. You only want to return an error if all iterations failed. Unindent the else block to do this.
for x in xrange(0,len(chars)-1):
if code == ord(chars[x]):
return chars[x]
else:
return "wat"
The else block is optional. You could also write:
for x in xrange(0,len(chars)-1):
if code == ord(chars[x]):
return chars[x]
return "wat"

Related

is there a simpler way to complete the following exercise? I am adding elements to a string, depending on three conditions

From Google Python Class
D. Verbing :
Given a string, if its length is at least 3, add 'ing' to its end.
Unless it already ends in 'ing', in which case add 'ly' instead.
If the string length is less than 3, leave it unchanged.
Return the resulting string.
def verbing(s):
if len(s) < 3:
return s
if len(s) >= 3 and s[-3:] == 'ing':
s = s + 'ly'
return s
elif s[:-3] != 'ing':
s = s + 'ing'
return s
Test Cases
print 'verbing'
test(verbing('hail'), 'hailing')
test(verbing('runt'), 'runting')
test(verbing('swiming'), 'swimingly')
test(verbing('do'), 'do')
test(verbing('hi'), 'hi')
You can use str.endswith:
test_cases = ["ing", "webbing", "xy", "house"]
def verbing(s):
return s if len(s) < 3 else (s + "ly" if s.endswith("ing") else s + "ing")
for t in test_cases:
print(t, verbing(t))
Prints:
ing ingly
webbing webbingly
xy xy
house houseing
Your control flow statements (if/elif/else) all end with return s, so you could restructure things to eliminate the redundant return s statements:
def verbing(s):
if len(s) >= 3:
if s[-3:] == 'ing':
s = s + 'ly'
elif s[:-3] != 'ing':
s = s + 'ing'
return s
This also eliminates the if len(s) < 3 line, since if len(s) isn't greater than or equal to 3, that must mean it is less than 3, so there isn't much of a point in checking for that explicitly.
Similarly, since the if s[-3:] == 'ing' line asks "does this end in -ing? yes or no?", if the answer is not "yes", it must be "no" (or in this case, False). So the elif statement can be replaced with a simpler and more efficient else (more efficient since it's not checking & evaluating another condition). You can also shorten s = s + something statements to s += something, which is a bit shorter and nicer to read:
def verbing(s):
if len(s) >= 3:
if s[-3:] == 'ing':
s += 'ly'
else:
s += 'ing'
return s
Finally, there's a shorter way to write simple if/else statements which in other languages is known as the ternary operator, which applied here would look something like this:
def verbing(s):
if len(s) >= 3:
# the parentheses are not needed but do
# help make it more clear what's going on
s += ('ly' if s[-3:] == 'ing' else 'ing')
return s
This ('ly' if s[-3:] == 'ing' else 'ing') statement gets evaluated in the same way as the previous if/else statement, just written in a different way. It can be read as "this statement should be equal to 'ly' if the string ends in 'ing'; otherwise, this statement should be equal to 'ing'." The value of that statement is what will get tacked onto the end of the string s.
Ultimately, I think the code you began with is a good place to start, since it does in fact work. And you're right to want to review that code to see if there are places where it could be cleaner, shorter, and/or more efficient. This is roughly how I personally go about these sorts of things and I hope this may help you in the process of improving and refactoring the code you write in future. Good luck and have fun!
Here's what I could come up with on a short notice:
def verbing(string: str) -> str:
if len(string) >= 3:
if not string.endswith("ing"):
string += "ing"
else:
string += "ly"
return string
Hope that helps.
There are many different ways to solve this problem. I think that first you need to ask yourself why your solution isn't good enough. Maybe if you will run import this you will understand better how code in python should look like and what are the values that you should follow.
Although this pattern is way to much for this small problem, for education purpose I will intrude another pattern that can be handy if the problem should be address from the scale point of view.
def cond_ing(st):
return st[-3:] != "ing"
def add_ing(st):
return st + "ing"
def cond_ly(st):
return st[-3:] == "ing"
def add_ly(st):
return st + "ly"
d = {
cond_ing: add_ing,
cond_ly: add_ly
}
now you can run a simple for loop and every one can just add which condition that they would like. something like:
for s in tests:
if len(s) <= 3:
print(s)
continue
for con in d:
if con(s):
print(d[con](s))

How to break a condition statement and go to elif/else once reached inside the condition block?

I have an if/elif/else block in my code, however, I figured out that there is a time my code goes through the elif statement but by the end of the elif block I realized that my inputs are not being applied to the code inside. So that means I needed to check the next elif/else. Is there a way I can break the current "condition" block and consider it as if it was not visited?
I won't be able to share my code but I can try to give you an example:
group = [A, B, C]
if condition:
pass
elif len(group) >= 3:
for each in group:
if not processed(each):
process(each)
else:
# do something else
There is a lot going through the if block, but there is a time everything in the group is processed, and I would like to still visit the else block if that happens as if I never went through the elif block.
You could change the else to an if and use a boolean. It is a bit hackish though...
do_else_block = True
if condition:
do_else_block = False
pass
elif len(group) >= 3:
for each in group:
if not processed(each):
do_else_block = False
process(each)
if do_else_block:
# do something else
Not all of your code needs to be in an if or else block. If you want something to happen regardless of the if condition, just unindent it.
group = [A,B,C]
if not condition and len(group) >=3: # combine the two checks into one "if"
for each in group:
if not processed(each):
process(each)
do something else # this happens regardless because it's not in an "else"
Going off the interpretation in Solomon's answer, I'd express that same logic as:
if len(group) >= 3 and not condition:
to_process = [e for e in group if not processed(e)]
else:
to_process = []
for each in to_process:
process(each)
if not condition and not to_process:
# do something else

What is wrong with my python hyperoperation recursive function?

I tried to use the definition from Wikipedia for Hyperoperations and translate it into Python code.
My goal was to make it readable, making it fast was a task for later.
Here's the definition I used and below it is my code.
from Wikipedia: https://en.wikipedia.org/wiki/Hyperoperation#Definition
And now here's my code:
def hyperation(n, a, b):
if n == 0:
return b+1
if n == 1 and b == 0:
return a
if n == 2 and b == 0:
return 0
if n >= 3 and b == 0:
return 1
return hyperation(n-1, a, hyperation(n, a, b-1))
When I tried it with hyperation(n=1, a=3, b=3), what should basically be the same as
3 + 3
I always hit the recursion limit, doesn't matter how high I set it.
When trying this on paper by hand, it works perfectly fine. And while debugging I couldn't figure out what happens.
Thanks for every help!!!
In your last line the return keyword is missing.
First, your code was not formatted right, cause python is a indentation sensitive language.
Second, The last line of the error log indicates that the error is the addition of NoneType and int. You didn't return anything in the final else block, so that will return NoneType. Just add return at the beginning of the last sentence.
Third, you can delete every elif after return and just use if.

A statement that has the same indentation with its previous "if" statement will always be executed?

I'm attending an online course on Python.
if <TestExpression>:
<block>
i=21
Regarding the above code ("code1"), the lecturer said that i=21 will execute, whether or not the test expression is true, because i=21 has the same indentation with the if statement, meaning i=21 is not part of the if statement.
However, the lecturer also said the following code ("code2"):
def bigger(a,b):
if a>b:
return a
return b
is the same as the following code ("code3"):
def bigger(a,b):
if a>b:
return a
else:
return b
Doesn't this contradict what he previously said? i=21 in code1 and return b in code2 both have the same indentation with their previous if statements, but why i=21 will always execute no matter the test expression is true or false, while return b will execute only when the test expression (a>b) is false?
How do you decide whether the statement immediately following the if construct which has the same indentation with the if line should execute? In another word, how do you decide whether that statement is part of the if construct?
This is a great question you have asked, and it's an issue a lot of new people have with functions specifically.
The issue lies with the return keyword. In a function, when it returns a value, the function immediately breaks. Thus, no subsequent code in the function is run. Because of this, we can short-hand our conditional statements to:
if a > b:
return a
# Function breaks here - no more code is executed.
# This bit is never reached if a is returned
return b
Observe:
def test():
if 10 > 5:
print("Hello!")
return True
print("Hi!")
return False
When we call test(), only Hello! is printed.
One reason this is helpful is to stop erroneous whitespace when having multiple conditional statements in Python. Of course, in most other programming languages, since whitespace isn't a feature, it's not as necessary.
Imagine you were writing a function to check if a number was prime, where lots of conditional statements were required. (Of course, for the sake of this example, this isn't efficient):
def is_prime(n):
if n == 1:
return False
else:
if n == 2:
return True
else:
for i in range(2, n):
if n % i == 0:
return False # A factor exists
else:
continue
return True
Knowing that a return breaks the function, we can re-write this as:
def is_prime(n):
if n == 1:
return False
if n == 2:
return True:
for i in range(2, n):
if n % i == 0:
return False # A factor exists
return True
See how the indentation is so much cleaner?
That's because you can't return twice from a function. When if is satisfied, it will return and won't execute any more statement. So, the next return statement is unreachable.
The next return will only execute when if is failed. else is also executed when if is failed.
That's why your teacher says, both of them are same.

Python does not allow multiple return() statements in ternary; possible alternative that is also aesthetically pleasing?

I am developing a text based RPG (graphics will be implemented later) and I am writing a method to determine whether a room a player is trying to go to exists or not. In this method I have multiple logic statements that determine what room the player is trying to get to based on the direction they enter and whether that "room" == 0 (my place holder for an empty space in the world/dungeon array). Although I can write a conventional logic statement for this:
if condition:
if otherCondition:
return(True)
else:
return(False)
a ternary is much more aestheticaly pleasing:
if condition:
return(True) if otherCondition else return(False)
But of course, that does not work. I am looking for something that functions as the conventional logic statement but is also "pleasing to the eye", like a ternary. In my code the logic statement is repeated four times, and the conventional logic statement would be displeasing to read.
I am using Python 3.5.1 on Windows 7.
The issue with your statement isn't the ternary part, it's the repeated return. Instead use:
if condition:
return True if otherCondition else False
Here, the result of the expression True if otherCondition else False is returned.
This could be written more concisely as:
if condition:
return bool(otherCondition)
Use just a single return with ternary statement:
return 'something' if someCondition else 'something else'
For you case is enough just :
if condition:
return otherCondition
# or if "otherCondition is not bool you can use: return bool(condition)
z = x if success else y
# this tallies z = success ? x : y, where success is a bool. Either True or False
Here the expression on the right returns x or y depending on if success evaluates to True or False respectively. As this is an expression it can be used with a return statement
return x if success else y
if condition:
return othercondition
Perhaps you should illustrate with an example, because it can be simplified to return the result of the other condition.
if condition:
return otherCondition
What ever happened to just:
if condition:
# tis very simple; if room is equal to 0, the operation is true, thus `True` will be returned
# otherwise `False`.. no mystery
return room == 0

Categories