Checking for user input without using "if" statement? - python

For my homework assignment, I'm trying to think of a way to check for user input without using the if statement.
This would be how the algorithm is implemented with an "if" statement
if userInput == "books":
printBooks()
else:
addBooks()
Is there a way to implement the same thing without using an if statement?

If you just do not want to see if in the code, this is the way to do:
func = {"book": printBooks}
func.get(userInput, addBooks)()
You put function as an object to a dict, retrieve it based on user input as the key, with a default fallback, then call the function.
And, yes, this is a bad approach in practice.

Don't ever see a need for this, but:
(addBooks, printBooks)[userInput == "books"]()

For python you can use like this
bookData = printBooks() if userInput == "books" else addBooks()

Related

I can't put "continue" command in a definition?

Let's say,
def sample():
if a==1:
print(a)
else:
continue
for i in language:
a=i
sample()
I want to use this function in a loop, but the continue command gives me an error because there is no loop. What can I do?
Return a boolean from the function and based on the return value make continue or not because continue must be within a loop
continue keyword in python is only available in for or while loops. Also block defined variables like a are not available on the global scope.
I don't know what you want to achieve but assuming your code, you want to extract a condition into a function, something like this:
def condition(a):
return a == 1
def sample(a):
print(a)
for i in language:
a=i
if condition(a):
sample(a)
else:
continue
There are several best-practice patterns of exactly how to do this, depending on your needs.
0. Factor your code better
Before doing any of the below, stop and ask yourself if you can just do this instead:
def sample(a):
print(a)
for i in language:
if i != 1:
continue
sample(i)
This is so much better:
it's clearer to the reader (everything you need to understand the loop's control flow is entirely local to the loop - it's right there in the loop, we don't have to look anywhere else farther away like a function definition to know when or why or how the loop will do the next thing),
it's cleaner (less boilerplate code than any of the solutions below),
it's more efficient, technically (not that this should matter until you measure a performance problem, but this might appeal to you; going into a function and coming back out of it, plus somehow telling the loop outside the function to continue - that's more work to achieve the same thing), and
it's simpler (objectively: there is less code complected together - the loop behavior is no longer tied to the body of the sample function, for example).
But, if you must:
1. Add boolean return
The simplest change that works with your example is to return a boolean:
def sample(a):
if a==1:
print(a)
else:
return True
return False
for i in language:
if sample(i):
continue
However, don't just mindlessly always use True for continue - for each function, use the one that fits with the function. In fact, in well-factored code, the boolean return value will make sense without even knowing that you are using it in some loop to continue or not.
For example, if you have a function called check_if_valid, then the boolean return value just makes sense without any loops - it tells you if the input is valid - and at the same time, either of these loops is sensible depending on context:
for thing in thing_list:
if check_if_valid(thing):
continue
... # do something to fix the invalid things
for thing in thing_list:
if not check_if_valid(thing):
continue
... # do something only with valid things
2. Reuse existing return
If your function already returns something, or you can rethink your code so that returns make sense, then you can ask yourself: is there a good way to decide to continue based on that return value?
For example, let's say inside your sample function you were actually trying to do something like this:
def sample(a):
record = select_from_database(a)
if record.status == 1:
print(record)
else:
continue
Well then you can rewrite it like this:
def sample(a):
record = select_from_database(a)
if record.status == 1:
print(record)
return record
for i in language:
record = sample(a)
if record.status != 1:
continue
Of course in this simple example, it's cleaner to just not have the sample function, but I am trusting that your sample function is justifiably more complex.
3. Special "continue" return
If no existing return value makes sense, or you don't want to couple the loop to the return value of your function, the next simplest pattern is to create and return a special unique "sentinel" object instance:
_continue = object()
def sample(a):
if a==1:
print(a)
else:
return _continue
for i in language:
result = sample(i):
if result = _continue:
continue
(If this is part of a module's API, which is something that you are saying if you name it like sample instead of like _sample, then I would name the sentinel value continue_ rather than _continue... But I also would not make something like this part of an API unless I absolutely had to.)
(If you're using a type checker and it complains about returning an object instance conflicting with your normal return value, you can make a Continue class and return an instance of that instead of an instance of object(). Then the type hinting for the function return value can be a type union between your normal return type and the Continue type. If you have multiple control flow constructs in your code that you want to smuggle across function call lines like this.)
4. Wrap return value (and "monads")
Sometimes, if the type union thing isn't good enough for some reason, you may want to create a wrapper object, and have it store either your original return value, or indicate control flow. I only mention this option for completeness, without examples, because I think the previous options are better most of the time in Python. But if you take the time to learn about "Option types" and "maybe monads", it's kinda like that.
(Also, notice that in all of my examples, I fixed your backdoor argument passing through a global variable to be an explicit clearly passed argument. This makes the code easier to understand, predict, and verify for correctness - you might not see that yet but keep an eye out for implicit state passing making code harder to follow and keep correct as you grow as a developer, read more code by others, and deal with bugs.)
It is because the scope of the function doesn't know we are in a loop. You have to put the continue keyword inside the loop
continue keyword cannot be used inside a function. It must be inside the loop. There is a similar question here. Maybe you can do something like the following.
language = [1,1,1,2,3]
a = 1
def sample():
if a == 1:
print(a)
return False
else:
return True
for i in language:
if sample():
continue
else:
a = i
OR something like this:
language = [1,1,1,2,3]
a = 1
def gen(base):
for item in base:
if a == 1:
yield a
else:
continue
for i in gen(language):
a = i
print(a)

Using dictionary mapping to call functions from Keyboard Input

I have several pre-defined functions in a dictionary:
dict = {
'test1':test1(),
'test2':test2(),
'test3':test3()
}
At this point I already have a question: after creating the dictionary these functions run automatically - why is that and how can I avoid it?
Ultimately, my goal is to type in e.g. "test2" and get the function executed (just the one in a controlled manner, not everything at once like above). First I wanted to use eval, but everyone advised against it, which I understand now. But what is the alternative? I tried
def select_function():
try:
return dict[input("Type in function ")]
except KeyError:
raise ValueError('Invalid input!')
select_function()
as well as just
dict.get(input("Type in function "), 'Invalid input!')
But both return an empty line if I type in the correct function. If I type in a wrong one I get my error message, therefore my command should work in general. I also know my functions work because, as I said, they get executed after I create the dictionary and they only print a greeting (a different one for each function for testing).
Did I do something wrong? Is there some other way to call functions without eval()?Thanks in advance.
Do it like
dict = {
'test1':test1,
'test2':test2,
'test3':test3
}
Then
return dict[input("Type in function")]
If you want to call that function, Just
return dict[input("Type in function")]()

My information won't write to a file? - Python

I'm fairly new to Python, I'm learning it at school and I've been messing around with it at home, I'd like to learn it better for when GCSE's hit just to make it easier.
I'm having an issue with the code below:
def takeinfo():
print("To begin with, would you like to write your file clean? If you're making a new file, yes.")
choice=input()
if 'Y' or 'yes' or 'Yes' or 'YES' in choice:
print("What would you like to write in the file? \n")
information=input()
writeinfo()
else:
exit()
def writeinfo():
a=open('names.txt','wt')
a.write(information)
a.close()
takeinfo()
When I type 'Yes' to be taken to the writeinfo() definition, it doesn't write the information I'm asking it to because it's unassigned, even after typing something in the takeinfo() definition? Any help would be appreciated. I understand this is simple, but I've looked at other questions and I can't seem to find what's wrong with my code.
Thankyou.
def writeinfo():
a=open('names.txt','wt')
a.write(information)
a.close()
the "information" needs to be passed into the writeinfo function
should be:
def writeinfo(information):
a=open('names.txt','wt')
and above, when the function is called:
print("What would you like to write in the file? \n")
information=input()
writeinfo(information)
You will need to pass the argument on like this:
def takeinfo():
# same as before
information=input()
writeinfo(information)
# else stays the same
def writeinfo(information):
# rest remains the same...
takeinfo()
Or just change information into the global scope using global.
And a hint for you:
if 'Y' or 'yes' or 'Yes' or 'YES' in choice:
Wouldn't work as you would've expected. You can do some extensive learning to figure out why it will always be True even if the user inputted "No".
other answers show good functional style (pass information to the writeinfo() function)
for completeness' sake, you could also use global variables.
the problem you are facing is, that the line
information=input()
(in takeinfo()) will assign the input to a local variable, that shadows the global variables of the same name.
in order to force it to the global variable, you have to explicitely mark it as such, using the global keyword.
other problems
input vs raw_input
input() in python3 will just ask you to input some data.
however, in Python2 it will evaluate the user-data. on py2 you should therefore use raw_input() instead.
has the user selected 'yes'?
there's another problem with your evaluation of choice (whether to write to file or not).
the term 'Y' or 'yes' or 'Yes' or 'YES' in choice always evaluates to true, since it is really interpreted as ('Y') or ('yes') or ('Yes') or ('YES' in choice), and bool('Y') is True.
instead, you should use choice in ['Y', 'yes', 'Yes', 'YES'] to check whether choice is one of the items in the list.
you can further simplify this by normalizing the user answer (e.g. lower-casing it, removing trailing whitespace).
solution
try:
input = raw_input
except NameError:
# py3 doesn't know raw_input
pass
# global variable (ick!) with the data
information=""
def writeinfo():
a=open('names.txt','wt')
a.write(information)
a.close()
def takeinfo():
print("To begin with, would you like to write your file clean? If you're making a new file, yes.")
choice=input()
if choice.lower().strip() in ['y', 'yes']:
print("What would you like to write in the file? \n")
global information
information=input()
writeinfo()
else:
exit()

Mapping a returned string to a specific function

I have router that is deciding which function to call based upon user input (uses ConfigParser) and then tries to decide which function to call.
def SomethingElse():
print 'hello'
def UploadDirectory():
print 'hi'
def router(config):
if config.has_option('job', 'Some_Task'):
taskName = config.get('job', 'Some_Task')
# taskName is now 'UploadDirectory'
###execute the UploadDirectory function
###execute something else if something else, etc
So what is the way to write this in python? If I prebuilt a map of functions to strings, can i execute them that way?
How would you write this?
Yep, building a map of strings to function names is perfectly valid:
task_map = {
'upload': UploadDirectory,
'something': SomethingElse,
}
And execute as:
task_map[task_name]()
Aside: try to follow PEP-8, the python style guide; it helps make your code more readable to all other Python programmers. Specifically in this case, prefer underscore_separated function names instead of LeadingCaps.
Another hacky way to do it is to use globals(), if you're not running just by importing the router function:
globals()[taskName]()

Python return values?

How do I do this? Can I do this?
def aFunction(argument):
def testSomething():
if thisValue == 'whatItShouldBe':
return True
else:
return False
if argument == 'theRightValue': # this is actually a switch using elif's in my code
testSomething()
else:
return False
def aModuleEntryPoint():
if aFunction(theRightValue) == True:
doMoreStuff()
else:
complain()
aModuleEntryPoint()
aModuleEntryPoint() needs to first make sure that a condition is true before it starts doing things. Because of encapsulation, aModuleEntryPoint doesn't know how to check the condition, but aFunction() has a sub-function called testSomething() that does know how to check the condition. aModuleEntryPoint() calls aFunction(theRightValue).
Because theRightValue was passed to aFunction() as an argument, aFunction() calls testSomething(). testSomething() performs the logic test, and either returns True or False.
I need for aModuleEntryPoint() to know what testSomething() decided. I do not want aModuleEntryPoint() to know anything about how testSomething() came to its conclusion.
It would actually be an accomplishment to post my actual source while removing other functions and what-not, so I had to setup the general gist like this.
The only thing I see wrong right now is you need a return before testSomething() on line 9.
Perhaps a sub-function is not the right encapsulation tool for you here. You want to expose internal functionality to an external entity. Python classes provide a better mechanism for expressing this than sub-function. Having a class, you can expose whatever parts of internal functionality you want in a very controlled manner.
My first thought upon looking at your code is that it's a little too complicated. Why have aFunction at all? You could just write
def aModuleEntryPoint():
argument = ...
if argument in (theRightValue, theOtherRightValue, theOtherOtherRightValue)\
and testSomething():
doMoreStuff()
else:
complain()
This if clause will first check whether argument is one of the possible right values, and if it is, then it will proceed to call testSomething() and check the return value of that. Only if that return value is true will it call doMoreStuff(). If either of the tests fails (that's why I used and), it will complain().

Categories

Resources