define function as dictionary value to check conditions - python

I want to create a dictionary that has keys and values, values has to be 3 elements long list. the first is a string that asks for input, the second a function that check a condition and the third a string to print if the condition is false
dict = {
'input 1': ['number > 10', def check(n): pass if n > 10 else raise ValueError, 'the number must be gratere than 10'],
'input 2': ['3 words', def check(text): pass if len(text) == 3 else raise ValueError, 'must be 3 words'],
'input 3': ['name', def check(text, name_list): pass if text in name_list else raise ValueError, 'the name has to be one of them '.format(x = name_list)]
}
for i in dict:
while True:
text = input(dict[i][0])
try:
dict[i][1](text)
break
except ValueError:
print(dict[i][2])
I know this is very strange but the dict is very long and with very different conditions.
I don't even know how can I pass multiple arguments to the funcs that need more than one

This does what you ask. Take some time to note the changes I've made here.
Note that the functions must all accept the same parameters.
def check_num( val ):
n = int(val )
if n <= 10:
raise ValueError( 'the number must be greater than 10' )
def check_3( val ):
if len(val.split()) != 3:
raise ValueError( 'must be 3 words' )
def check_name( val ):
if text not in name_list:
raise ValueError( 'the name must e one of' + (' '.join(name_list)) )
data = {
'input 1': ['Enter number', check_num],
'input 2': ['Enter 3 words', check_3],
'input 3': ['Enter a name', check_name]
}
name_list = ['Bill', 'Ted', 'Tom']
for i,info in data.items():
while True:
text = input(info[0]+': ')
try:
info[1](text)
break
except ValueError as e:
print( e )

If all your functions take only the input text as argument, make your function return a bool value:
dict = {
'input 1': ['number > 10', lambda n: n > 10, 'the number must be gratere than 10'],
'input 2': ['3 words', lambda text:len(text) == 3, 'must be 3 words'],
'input 3': ['name', lambda text: text in name_list, 'the name has to be one of them '.format(x = name_list)]
}
for i in dict:
while True:
text = input(dict[i][0])
res = dict[i][1](text)
if res:
break
else:
print(dict[i][2])
There is no easy way to make your third function work, because it requires a different number of arguments, I suggest setting name_list as a global variable.

Use lambda to create function expressions in the list, not def. But lambda can only contain a single expression to evaluate and return; pass and raise are statements, not expressions.
So you'll need to define these functions outside the dictionary, then reference them there.
And since you never use the dictionary keys, iterate over the values().
Don't use dict as a variable name, it overwrites the built-in class with that name.
name_list will need to be a global variable. All the check functions can only take 1 argument, since the loop has no way of knowing that some functions require additional arguments. It just passes the input text.
def check_greater_10(n):
if n <= 10:
raise ValueError
def check_3_words(text):
if len(text.split()) != 3:
raise ValueError
def check_name_list(text):
if text not in name_list:
raise ValueError
mydict = {
'input 1': ['number > 10', check_greater_10, 'the number must be greater than 10'],
'input 2': ['3 words', check_3_words, 'must be 3 words'],
'input 3': ['name', check_name_list, 'the name has to be one of them: {x} '.format(x = name_list)]
}
for prompt, check, error in mydict.values():
while True:
text = input(prompt)
try:
prompt(text)
break
except ValueError:
print(error)

get input using realdlines() function:
import sys
inputx = sys. stdin. readline()
print(inputx)
for no of lines use sys.stdin.readlines() but it must be given under for loop with range

Related

Trying to get ORF's from a given DNA sequence

I am trying to get a printed output which would be everything from the beginning of the string, to the end, which is until it reaches a certain series of characters like "TAA", "TAG", or "TGA".
I can't get it to work and was wondering if anyone here can help me??
def get_orf(dna):
'''Function should take an argument (string) and find an ORF'''
stopVar = "TAA" or "TGA" or "TAG"
if argument[0:3] == "ATG":
return
else:
return ""
if stopVar in argument:
return argument[:argument.find(stopVar)]
else:
return argument
return
# Test Cases
#
# You may wish to add more test cases here
argument = 'ATGTGAA'
computed_result = get_orf( argument )
expected_result = 'ATG'
if ( computed_result == expected_result ):
print ("Test Case 1: Passed")
else:
print ("Test Case 1: Failed")
print ("Expected Result:", expected_result)
print ("Computed Result:", computed_result)
This works although I am not sure whether you want to return something if the case 'ATG' is found, it is good practice that if one of your returns in a function returns something, then they all should even if it is None:
def get_orf(dna):
"""Function should take an argument (string) and find an ORF."""
stopVar = "TAA" or "TGA" or "TAG"
if dna[0:3] == "ATG":
return "ATG"
elif stopVar in dna:
return dna[:dna.find(stopVar)]
else:
return dna
# Test Cases
#
# You may wish to add more test cases here
argument = 'ATGTGAA'
computed_result = get_orf(argument)
expected_result = 'ATG'
if (computed_result == expected_result):
print ("Test Case 1: Passed")
else:
print ("Test Case 1: Failed")
print ("Expected Result:", expected_result)
print ("Computed Result:", computed_result)
With argument = 'ATGTGAA':
Test Case 1: Passed
With argument = 'GATGTGAA':
Test Case 1: Failed
Expected Result: ATG
Computed Result: GATGTGAA
The docstring for functions is with """Text.""" rather then single quotes too so I changed that.

Is there a way to remove too many if else conditions?

I am currently making an interactive system using python, that is able to understand and reply. Hence for this there are lots of conditions for machine to analyze and process. For eg. take the following code(for reference only):
if ('goodbye') in message:
rand = ['Goodbye Sir', 'Jarvis powering off in 3, 2, 1, 0']
speekmodule.speek(rand,n,mixer)
break
if ('hello') in message or ('hi') in message:
rand = ['Wellcome to Jarvis virtual intelligence project. At your service sir.']
speekmodule.speek(rand,n,mixer)
if ('thanks') in message or ('tanks') in message or ('thank you') in message:
rand = ['You are wellcome', 'no problem']
speekmodule.speek(rand,n,mixer)
if message == ('jarvis'):
rand = ['Yes Sir?', 'What can I doo for you sir?']
speekmodule.speek(rand,n,mixer)
if ('how are you') in message or ('and you') in message or ('are you okay') in message:
rand = ['Fine thank you']
speekmodule.speek(rand,n,mixer)
if ('*') in message:
rand = ['Be polite please']
speekmodule.speek(rand,n,mixer)
if ('your name') in message:
rand = ['My name is Jarvis, at your service sir']
speekmodule.speek(rand,n,mixer)
So, is there a way in which I can replace all these if else conditions?? Because there are much more conditions going to be, and it will make the execution slower.
Make a exclusive "if":
if 'goodbye' in message:
rand = ['Goodbye Sir', 'Jarvis powering off in 3, 2, 1, 0']
elif 'hello' in message or 'hi' in message:
rand = ['Wellcome to Jarvis virtual intelligence project. At your service sir.']
elif 'thanks' in message or 'tanks' in message or ('thank you') in message:
rand = ['You are wellcome', 'no problem']
elif message == 'jarvis':
rand = ['Yes Sir?', 'What can I doo for you sir?']
elif 'how are you' in message or 'and you' in message or ('are you okay') in message:
rand = ['Fine thank you']
elif '*' in message:
rand = ['Be polite please']
elif 'your name' in message:
rand = ['My name is Jarvis, at your service sir']
else:
raise NotImplementedError("What to do?")
speekmodule.speek(rand, n, mixer)
With a mapping of RegEx:
mapping = {
r"\bgoodbye\b": ['Goodbye Sir', 'Jarvis powering off in 3, 2, 1, 0'],
r"\bhello\b": ['Wellcome to Jarvis virtual intelligence project. At your service sir.'],
...}
for regex, rand in mapping.items():
if re.search(message, flags=re.I):
break
else:
raise NotImplementedError("What to do?")
speekmodule.speek(rand, n, mixer)
It's up to you to decide.
if/elif/else is a natural way to structure this kind of code in Python. As #imant noted, you may use dict-based approach in case of simple branching, but I see some mildly complex logic in your if predicates, so you'll have to check all predicates in any case and you won't have any performance gains with another code structure.
Though it may be a little bit more readable and easier to maintain if you factor out your predicates and actions like this:
from collections import OrderedDict
def goodbye_p(message):
return 'goodbye' in message
def goodbye_a():
rand = ['Goodbye Sir', 'Jarvis powering off in 3, 2, 1, 0']
# As #Moinuddin Quadri I also assume that your `speek` method
# says random message from a list.
# Otherwise you can use `random.choice` method
# to get a random message out of a list: `random.choice(messages)`.
speekmodule.speek(rand, n, mixer)
def hello_p(message):
return 'hello' in message or 'hi' in message
def hello_a():
rand = ['Wellcome to Jarvis virtual intelligence project. At your service sir.']
speekmodule.speek(rand, n, mixer)
# Use `OrderedDict` instead of `dict` to control order
# of checks and actions.
branches = OrderedDict([
# (predicate as key, action as value)
(goodbye_p, goodbye_a),
(hello_p, hello_a),
])
for predicate, action in branches.items():
if predicate(message):
action_result = action()
# You can add some logic here based on action results.
# E.g. you can return some special object from `goodbye_a`
# and then shut down Jarvis here.
# Or if your actions are exclusive, you can add `break` here.
If all your predicates are the same and contain only substring checks, then it may be more performant to have tuples (e.g. ('hello', 'hi')) as dict keys. Then you can iterate over those keys like this:
for words, action in branches.items():
if any(word in message for word in words):
action()
Use dictionary:
someCollections = {
'goodbye': "Something1",
'hello': "Somthing2",
...
}
speekmodule(someCollections [SomeKey],...)
Firstly create a dict object with the key as tuple of string you want to match in your message and associate it with the value string which your Jarvis is suppose to respond. For example:
jarvis_dict = {
('goodbye',) : ['Goodbye Sir', 'Jarvis powering off in 3, 2, 1, 0'],
('hello',
'hi') : ['Wellcome to Jarvis virtual intelligence project. At your service sir.'],
('thanks',
'tanks',
'thank you') : ['You are wellcome', 'no problem'],
('jarvis',) : ['Yes Sir?', 'What can I doo for you sir?'],
('how are you',
'and you',
'are you okay'): ['Fine thank you'],
('*',) : ['Be polite please'],
('your name',): ['My name is Jarvis, at your service sir']
}
Now iterate each key of you dict to check whether any sub-string is the part of the message and if there is any match, call the speekmodule.speek(rand,n,mixer) function as:
for key, value in jarvis_dict.items():
if any(item in message for item in key):
speekmodule.speek(value, n, mixer)
Note: Here I am assuming that speekmodule.speek(value, n, mixer) in your code is working as there is no information available in your code regarding there declaration. I just replaced your rand with value as it the same list of str returned by the dict which is used in your code.

How do I Create a Loop from Raw_Input String Value

What I'm trying to do with my program is to ask a user to enter a input string that will later be converted to uppercase or lowercase using str.upper or str.lower.
I have 5 sets options that the user can chose:
a = 'convert to upper case'
b = 'convert to lower case'
c = 'switch case of every alphabetic character to the opposite case'
d = 'convert first and last chrs of each word to upper case, and others to lower'
e = 'no change'
So far I have done the conversion for options a and b. But before I move forward creating a code for options c, d and e. I'm trying to create a loop but I'm not sure how to do it using raw_input and strings.
This is the code that I have so far:
# Conversion Rules
a = 'convert to upper case'
b = 'convert to lower case'
c = 'switch case of every alphabetic character to the opposite case'
d = 'convert first and last chrs of each word to upper case, and others to lower'
e = 'no change'
def upper():
print 'Your Input: %s' % choice
print 'Choosen Conversion Rule: %s' % a
return 'Conversion Result: %s' % option_A
def lower():
print 'Your Input: %s' % choice
print 'Choosen Conversion Rule: %s' % b
return 'Conversion Result: %s' % option_B
choice = str(raw_input('Choose an Option:'))
if (choice == 'A') or (choice == 'a'):
value_A = str(raw_input('Enter a String to Convert:'))
option_A = str.upper(Value_A)
print upper()
elif (choice == 'B') or ('b'):
value_B = str(raw_input('Enter a String to Convert:'))
option_B = str.lower(value_B)
print lower()
else:
print 'Goodbye' # Here I want to break if 'Q' is entered if 'Q' is entered.
So after the user enters an option. For example 'A' or 'a'. The first condition will run but then I want to add a loop that goes back to the beginning of the code and allows the user to enter the option again or choose a different option so a different condition will run.
choice = str(raw_input('Choose an Option:'))
if (choice == 'A') or (choice == 'a'):
value_A = str(raw_input('Enter a String to Convert:'))
option_A = str.upper(Value_A)
print upper()
# I want to add a loop here to go back to the 'choice' variable.
You can put all of your user-interface inside a while loop that loops forever (until for example some key is presses).
# Conversion Rules
a = 'convert to upper case'
b = 'convert to lower case'
c = 'switch case of every alphabetic character to the opposite case'
d = 'convert first and last chrs of each word to upper case, and others to lower'
e = 'no change'
def upper():
print 'Your Input: %s' % choice
print 'Choosen Conversion Rule: %s' % a
return 'Conversion Result: %s' % option_A
def lower():
print 'Your Input: %s' % choice
print 'Choosen Conversion Rule: %s' % b
return 'Conversion Result: %s' % option_B
while True:
choice = str(raw_input('Choose an Option:'))
if (choice == 'A') or (choice == 'a'):
value_A = str(raw_input('Enter a String to Convert:'))
option_A = str.upper(Value_A)
print upper()
elif (choice == 'B') or ('b'):
value_B = str(raw_input('Enter a String to Convert:'))
option_B = str.lower(value_B)
print lower()
else:
print 'Goodbye' # Here I want to break if 'Q' is entered if 'Q' is entered.
break
Note that the "break" is what breaks you out of the loop. Since the user-interface part is in the while loop, it will repeat.

This tutorial on raising exceptions. I cant figure it out?

The instructions: Write a function validate_input(string) which takes a command string in the format 'command arg1 arg2' and returns the pair ('command', [arg1, arg2]), where arg1 and arg2 have been converted to floats. If the command is not one of 'add', 'sub', 'mul', or 'div', it must raise InvalidCommand. If the arguments cannot be converted to floats, it must raise InvalidCommand.
Typical inputs and outputs:
validate_input('add 2 3') -> ('add' [2. , 3.])
validate_input('hahahaha 2 3') -> Raises InvalidCommand()
validate_input('add six 3') -> Raises InvalidCommand()
Here is my code:
class InvalidCommand(Exception):
pass
def validate_input(string):
"""
validate_input(str) -> (str, [float])
If string is a valid command, return its name and arguments.
If string is not a valid command, raise InvalidCommand
Valid commands:
add x y
sub x y
mul x y
div x y
Arguments x and y must be convertable to float.
"""
# your code here
inlist = string.split(' ')
commands = []
strdigits = []
floats = []
output = []
for x in inlist:
if x.isdigit():
strdigits.append(x)
else:
commands.append(x)
for x in commands:
try:
x == 'add' or x == 'sub' or x == 'mul' or x == 'div'
output.append(x)
except ValueError:
raise InvalidCommand(ValueError)
for x in strdigits:
try:
float(x)
floats.append(float(x))
except ValueError:
raise InvalidCommand(ValueError)
output.append(floats)
return tuple(output)
When I test it on the values where it is supposed to raise InvalidCommand(), It tells me "Your code must raise InvalidCommand(). But my code does. I checked for typos and there are not any. So did I do the whole raising statement wrong? Please show me how to fix this. Thanks.
This line:
x == 'add' or x == 'sub' or x == 'mul' or x == 'div'
does nothing. It does not actually do anything with the result of your test, certainly it does not raise ValueError.
What you need is something like this:
if x.lower in ('add', 'sub', 'mul', 'div'):
output.append(x)
else:
raise InvalidCommand('unknown command: {}'.format(x))
Your code works for the numeric arguments because float() can raise ValueError if it is given a string that can not be converted to a float:
>>> float('abcd')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: could not convert string to float: abcd
Also, why you are passing ValueError as an argument to your custom exception? You might like to pass an error string that describes the nature of the error, e.g.
raise(InvalidCommand('arguments must be numeric: {}'.format(x))
or, you can pilfer ValueError's message:
try:
float(x)
floats.append(float(x))
except ValueError as exc:
raise InvalidCommand(exc)
You're making this way more complicated than it needs to be.
class InvalidCommand(Exception):
pass
def validate_input(datastr):
"""
validate_input(str) -> (str, [float])
If string is a valid command, return its name and arguments.
If string is not a valid command, raise InvalidCommand
Valid commands:
add x y
sub x y
mul x y
div x y
Arguments x and y must be convertable to float.
"""
inlist = datastr.split()
if len(inlist) != 3:
raise InvalidCommand('Bad command length: ' + str(len(inlist)))
x = inlist[0]
if x in ('add', 'sub', 'mul', 'div'):
cmd = x
else:
raise InvalidCommand('Bad command verb: ' + x)
floats = []
for x in inlist[1:]:
try:
floats.append(float(x))
except ValueError:
raise InvalidCommand('Bad command arg: ' + x)
return cmd, floats
#Test
data = [
'add 1 2',
'sub 3.0 2.0',
'mul 4.5 1.5',
'div 8 4',
'add 1 2 3',
'fred 2 3',
'add a b',
'sub 1 c',
]
for s in data:
try:
print(validate_input(s))
except InvalidCommand as e:
print(repr(s), e)
output
('add', [1.0, 2.0])
('sub', [3.0, 2.0])
('mul', [4.5, 1.5])
('div', [8.0, 4.0])
'add 1 2 3' Bad command length: 4
'fred 2 3' Bad command verb: fred
'add a b' Bad command arg: a
'sub 1 c' Bad command arg: c
I've changed the parameter of the validate_input function because string is the name of a standard Python module, so it can be confusing to use it for a simple variable name. And if you want to use that module then shadowing its name like that can lead to annoying bugs.
I did the same question for my uni subject csse1001. What I did was this:
# your code here
lst = string.split(' ')
commands = ['add', 'sub', 'mul', 'div']
if lst[0] not in commands:
raise InvalidCommand()
if len(lst) != 3:
raise InvalidCommand()
try:
arg1 = float(lst[1])
arg2 = float(lst[2])
return(lst[0], [arg1, arg2])
except ValueError:
raise InvalidCommand()
This worked for me.

Accessing Dictionary with Raw Input

I am trying to have a user input a 1,2,3,4,5,6.
Then have that integer align with a character name in my dictionary.
characters = {
'Stark': '1',
'Greyjoy': '2',
'California': '3',
'Whitewalkers': '4',
'Knights Watch': '5',
'Dalthraki': '6'
}
print 'Type 1 for Stark'
print 'Type 2 for Greyjoy'
print 'Type 3 for Lannister'
print 'Type 4 for Whitewalkers'
print 'Type 5 for Knights Watch'
print 'Type 6 for Dalthraki'
choice = raw_input("> ")
if choice in characters:
print 'You\'ve selected', choice
else:
splash()
I want to have my script print "You've selected Stark" after having the user input a 1.
Thanks for your help
You have the dict backwards:
characters = {
'1': 'Stark',
'2': 'Greyjoy',
'3': 'California',
'4': 'Whitewalkers',
'5': 'Knights Watch',
'6': 'Dalthraki',
}
print 'Type 1 for Stark'
print 'Type 2 for Greyjoy'
print 'Type 3 for Lannister'
print 'Type 4 for Whitewalkers'
print 'Type 5 for Knights Watch'
print 'Type 6 for Dalthraki'
choice = raw_input("> ")
if choice in characters:
print 'You\'ve selected', characters[choice]
else:
pass
change your dict to :
characters = {
'1':'Stark',
'2':'Greyjoy',
'3':'California',
'4':'Whitewalkers',
'5':'Knights Watch',
'6':'Dalthraki'
}
and use:
if choice in characters:
print 'You\'ve selected {0}'.format(characters[choice])
else:
splash()
You can't really use a dictionary that way. You can reverse the key/value pairs and then use characters[choice] to get the name of the character. If you want to preserve the dictionary as is, your best bet is to iterate over the items
characterName = None
names = characters.items()
while characterName is None and names:
if names[0][1] == choice:
characterName = names[0][0]
else:
names = names[1:]
After running this, you'll either have a character name in characterName, or it will be None if the user made an invalid entry.

Categories