I am trying to implement the switch in Dictionary in Python. But when I call the method
chooices.get(x, "Ther is no program") It call all the Function in the statment rather than calling x function.
I have read this implementation
Replacements for switch statement in Python?
but it was not helpful in my case as my function has print statement
Main file contain the code
from Day1.Day1 import Day1
from Day2.TipCalculator import TipCalculator
def choose():
print("Choose From the following Program:\n")
day1 = Day1()
day1.day1()
day2 = TipCalculator()
day2.day2()
x = int(input());
chooices={
1: day1.program1(),
2: day2.program1(),
}
chooices.get(x, "Ther is no program")
choose()
Day1 Class contain code
class Day1:
def day1(self):
print('1. Band name Generator\n')
def program1(self):
print('Welcome to Band Name Generator.\n')
cityName=input('What\'s is the name of city you grew up?\n')
petName = input('What\'s your pet\'s name?\n')
print('Your Band Name could be : '+cityName+" "+petName)
Class Tip Calculator Code
class TipCalculator:
def day2(self):
print("2. Tip Calculator For Bill.\n")
def program1(self):
print('Welcome to tip calculator.\n')
I just need the implementation Of switch statement which call Requested Program just like switch. I know Its possible through If-else but Dictionary mapping seems too be good alternative of switch
Overview: the interpretor creates a closure for the variables that the child function uses that are non local. In this example the child variable, value is 22 and stored in the closure cell.
def parent(arg_1, arg_2):
value=22
my_dict = {'chocolate':'yummy'}
def child():
print(2*value)
print(my['chocolate'])
print(arg_1 + arg_2)
return child
new_function=parent(3,4)
print(cell.cell_contents for cell in new_function.__closure__])
If you don't have a lot of variants, the if/elif/else statements can be streamlined using a helper function for the switch. This is only syntactic candy but it may be sufficient for small value sets.
def switch(v): yield lambda *c: v in c
Example usage:
x = int(input())
for case in switch(x):
if case(1): day1.program1()
elif case(2): day2.program1()
else: print("there is no program")
supporting multiple values for the same method call:
x = int(input())
for case in switch(x):
if case(1,5): day1.program1()
elif case(2,3,4): day2.program1()
else: print("there is no program")
you can also use it in a more C-like style
x = int(input())
for case in switch(x):
if case(1,5):
day1.program1()
break
if case(2,3,4):
day2.program1()
break
else:
print("there is no program")
If you have python 3.10 or higher, a proper switch analogue was implmemented called "match" which should work quite well in replacing any nested if statments the other answers may have.
If you dont have 3.10, and you are okay with a pretty hacky solution, mine uses the ideas from withhacks (specifically from AnonymousBlocksInPython). I have recently created my own version of a switch statment in python that acts more like how i am used to in C#. You can expand this as much as you want, way past single line arguments or assignments.
It uses context managers so that you can treat each case as its own code block with indentation and all. It will never enter the cases if the case value does not match the switch value so for code that is extremely system taxing, you can be sure it is not running code that does not need to be.
import sys
class CaseReturn(Exception):pass
class Case:
def __init__(self, caseVal): self._caseVal_ = caseVal
def _trace_(self,frame,event,arg): raise CaseReturn
def __enter__(self):
if self._caseVal_ == Switch._singleton_._switch_: return
sys.settrace(lambda *args, **keys: None)
sys._getframe(1).f_trace= self._trace_
def __exit__(self,ExType,ExVal,ExTrace):
if ExType is None: raise CaseReturn
return ExType is CaseReturn
class Switch:
_singleton_:'Switch' = None
def __init__(self, switchVal,Default=None): self._switch_ = switchVal
def __enter__(self):Switch._singleton_ = self
def __exit__(self,ExType,ExVal,ExTrace):
Switch._singleton_ = None
return ExType is CaseReturn
with Switch(2):
with Case(1):
print('This should not make it')
with Case(2):
print('I made it')
with Case(3):
print('This should never be called')
You can easily extend this out to check multiple cases by just changing the caseVal to a list and doing if Switch._singleton_._switch_ in self._caseVal_:
One caveat is, you cannot make the Case statments one-liners like:
Case(0): print('I am one line')
That will not work and end up calling the code in that case no matter what.
I hope this is useful to you or anyone who is searching for custom Switch statments!
Related
I am currently making a program with a text based menu, and I was wondering if there was anyway to avoid an excessive amount of if-statements while keeping it object oriented. I thought of something like this:
class Options:
def displayOptions():
#display user options
def option1():
#do option 1
def option2():
#do option 2
def option3():
#do option 3 and so on
class Menu(Options):
options = {1: option1(), 2: option2(), 3: option3()} #and so on
def promptUser():
#prompts user to make a choice
def printHeader():
#prints header
def handleInput():
#checks if input is valid
def begin():
#initialize menu
Would something like this be convoluted? Is the Options class pointless? I'm pretty new to OOP and I was wondering how this would most efficiently be done.
This is a bit hacky but it gets the job done.
class Options:
def doOption(self, opt):
option = f'option{opt}'
func = type(self).__dict__.get(option)
if hasattr(func, '__call__'):
return func(self)
raise ValueError(f'Unsupported option: {opt}')
class Menu(Options):
def option1(self):
print('Foo!')
def option2(self):
print('Bar!')
def optionbang(self):
print('Bang!')
menu = Menu()
menu.doOption(1) # Foo!
menu.doOption(2) # Bar!
menu.doOption('bang') # Bang!
What this does is look through the the class' properties and try to find a function (i.e., hasattr(func, '__call__')) with the right name. The nice thing is that the logic doesn't even require opt to be an integer.
That being said, if this is your only use case, then I agree with #GradyPlayer in the comments that the abstraction probably isn't worth it.
i have mentioned in store class method search to return None if the for loop end and still no return and in main i have written only if its a none then print nothing but it still prints "nothing"
i don't think there is any indentation as pointed out in questions of similar type
class book:
def __init__(self,_id,name,tech,price,auth):
self._id=_id
self.name=name
self.tech=tech
self.price=price
self.auth=auth
def _print(self):
print(self._id)
print(self.name)
print(self.tech)
print(self.price)
print(self.auth)
class store:
def __init__(self,bookdb,name='abc'):
self.bookdb=bookdb
self.name=name
def search(self,b_name,book_list):
for i in book_list:
if i.name==b_name:
return i._print()
else:
return None
def discount(self,tech,book_list):
amt=0
for i in book_list:
if i.tech==tech:
amt+=i.price
return amt*(0.9)
if __name__=="__main__":
t = int(input())
b_list=[]
bookdb=dict()
for i in range(t):
_id=int(input())
name=str(input())
tech=str(input())
price=int(input())
auth=str(input())
b_list.append(book(_id,name,tech,price,auth))
bookdb[i]=book(_id,name,tech,price,auth)
title=str(input())
tech=str(input())
store_i=store(bookdb)
if store_i.search(title,b_list)== None:
print('nothing')
else:
store_i.search(title,b_list)
if store_i.discount(tech,b_list)== 0:
print('0.0')
else:
print(store_i.discount(tech,b_list))
**Input**
3
1
TIC
CPP
300
Online
2
CR
JAVA
500
BSwamy
3
BR
JAVA
700
RAJA
TIC
JAVA
Output
1
TIC
CPP
300
Online
nothing
1080.0
output required
1
TIC
CPP
300
Online
1080.0
P.S. bookdb dic doesnt have any use here
The _print() method in class book has no return statement, so python will implicitly return None. Then in the search function, when you do return i._print(), it returns None as well, which is why you see the "nothing" output.
Since you're going to test the result, you might as well make search() return a boolean, here's a suggested edit:
def search(self,b_name,book_list):
for i in book_list:
if i.name==b_name:
i._print()
return True
else:
return False
You have a number of things wrong with your code.
First, if you are going to prompt input from the user, you should provide a message along with the prompt. Something like:
...
name=str(input("Enter Book Name: "))
...
Second, Python is very sensitive to the (visual) structure of your code (i.e. indentation levels). So for example, the "else" to your "if"s must always sit at the same indentation level.
def search(self,b_name,book_list):
for i in book_list:
if i.name==b_name:
return i._print()
else:
return None
Third, looking at this it's obviously not what you want. The return statement must come after the for loop
Fourth, returning i._print() isn't going to return i unless the _print function returns i as its last statement.
With these remarks, you should try
def search(self,b_name,book_list):
for i in book_list:
if i.name==b_name:
i._print()
return i
return None
Also, in general
Try giving your variable names that are descriptive. It was difficult to read and understand your code without using a debugger. You should be able to read it and understand as much as possible what it is doing. So variables like t or unobvious abbreviations should be avoided.
This goes along with prompting the user. If you are going to print things to the console, provide some text to explain what the user is reading. Something like:
...
print("Book Name: ", self.name)
...
There is more (Single Responsibility Principle,...), but this is a "okay" start. And you will learn more as you are moving forward.
So I'm trying to make a simple text based game from scratch, and I'm running into a problem right away. I'm trying to create a class for events that will happen in-game to make writing the code easier. Here's what I mean:
class event(object):
def __init__(self, text, trigger1, trigger2, outcome1, outcome2):
print(text)
time.sleep(1)
choice= input("What will you do?")
if choice == trigger1:
(Somehow execute outcome 1)
if choice == trigger2:
(Somehow execute outcome 2)
but I don't know how to make the outcomes contain code that I will write later, so any help would be appreciated!
The pythonic way is to use a dictionary with function objects:
def outcome1():
print("Outcome 1")
def outcome2():
print("Outcome 2")
def event(text, triggers):
print(text)
time.sleep(1)
choice= input("What will you do?")
triggers[choice]()
event("You can got west or east.", {
"go west": outcome1,
"go east": outcome2,
})
I do hope I'm understanding your question appropriately, so feel free to correct me if this isn't on target.
When you create a new instance of the class Event (and it's convention to capitalize the first character of classes). Assign a function to the value of outcome1 and outcome2, which will be executed according to their respective triggers.
def outcomeFunction1():
#Whatever you'd like to do for first outcome
print("Hello")
def outcomeFunction2():
#Whatever you'd like to do for second outcome
print("Bye")
Event('text', 'trigger1', 'trigger2', outcomeFunction1(), outcomeFunction2())
In your class definition write:
if choice == trigger1:
outcome1
elif choice == trigger2:
outcome2
Hope this helps!
Why is this in init? Are you really going to create new instance on every new event? To your question, if I got your question correctly, then this is code you may want to have.
def outcome1(text):
print("outcome1: %s" % text)
def outcome2(text):
print ("outcome2: %s" % text)
trigger_map = {
trigger1 : outcome1,
trigger2 : outcome2,
}
class event(object):
def __init__(self, trigger_map):
sefl._tmap = trigger_map
def onEvent (self, text):
print(text)
time.sleep(1)
choice= input("What will you do?")
return self._tmap [choice] (text)
Sorry if I misunderstood your question, but here I go...
The answer here depends on whether you want to have to make a new instance for every event. If you do, the code might look something like this (and as Jeremy E. pointed out, it's a good idea to capitalize the first character of classes):
class Event:
def __init__(self, text, question, trigger1, trigger2, outcome1, outcome2):
self.text, self.question = text, question
self.trigger1, self.trigger2 = trigger1, trigger2
self.outcome1, self.outcome2 = outcome1, outcome2
def get_choice(self):
print(self.text)
self.choice = input(self.question)
def execute(self):
if self.choice == self.trigger1:
exec(self.outcome1)
if self.choice == self.trigger2:
exec(self.outcome2)
I used the exec function to execute the outcomes. I moved some of the code to different functions, leaving the __init__ function to save the variables for the other functions. Then, you can make an instance for each event, like this:
room = Event("You are in a room with exits to the north and east.", "Where will you go?", "north", "east", "print('You went north.')", "print('You went east.'")
Notice I also added a question parameter, as to not force the What will you do? question on every event.
Now, if you wanted to only need one instance of the Event class, the code is a bit different:
class Event:
def make_event(self, text, question, trigger1, trigger2, outcome1, outcome2):
print(text)
choice = input(question)
if choice == trigger1:
exec(outcome1)
if choice == trigger2:
exec(outcome2)
You can see that the code is much shorter. To create an event with this, you would do something like this (with the same example as before):
event = Event() # This is only needed once, at the start of the program
event.make_event("You are in a room with exits to the north and east.", "Where will you go?", "north", "east", "print('You went north.')", "print('You went east.')")
EDIT: You may want to remove the class definition entirely, leaving just the make_event function I wrote for you above.
You can choose between either of these class examples, or use their ideas to make a customized one. I hope I answered your question.
Trying to make my own RPG character generator for ex 45 in Zed Shaw's LPTHW. Part of the assignment is to make a new class for each 'room' of the program, like WelcomeScreen or ChooseMutations.
Here is the main program.
import rooms
class Program(object):
def __init__(self, start):
self.start = start
def run(self):
next_room_name = self.start
while True:
room = getattr(self, next_room_name)
next_room_name = room()
x = rooms.WelcomeRoom()
Program(x.hello_user())
And here is the rooms file its trying to pull stuff from.
class WelcomeRoom(object):
def __init__(self):
pass
def hello_user(self):
print '*' * 79
print '\n'
print '\t\tWelcome to the'
print '\t\tMetamorphosis Alpha Character & Random Encounter Generator'
print '\t\tProgrammed poorly by Raymond Weiss'
print '\n'
print '*' * 79
raw_input('Please press enter to continue')
return 'get_name'
def get_name(self):
name = raw_input('Hello, whats your name?',
'\n',
':> ')
But when I run the main program in python, it just logs out instead of returning the function get_name() from rooms. Output posted below.
Raymond-Weisss-MacBook-Pro:macgre Raylug$ python macgre.py
*******************************************************************************
Welcome to the
Metamorphosis Alpha Character & Random Encounter Generator
Programmed poorly by Raymond Weiss
*******************************************************************************
Please press enter to continue
Raymond-Weisss-MacBook-Pro:macgre Raylug$
I apologize in advance if my question title isn't exactly what im trying to ask, as a newbie its sometimes hard not knowing what exactly to ask.
You're returning a string, not a function (or function result). You probably want something like:
def hello_user(self):
return self.get_name
or
def hello_user(self):
return self.get_name()
Based on your program, I think you probably want the second one. The difference is that the first one returns the get_name function, whereas the second one returns the results of the get_name function.
For brevity, I'm just showing what can/must occur in states. I haven't run into any oddities in the state machine framework itself.
Here is a specific question:
Do you find it confusing that we have to return StateChange(...) and StateMachineComplete(...) whereas some of the of the other actions like some_action_1(...) and some_action_2(...) need not be returned - they're just direct method invocations?
I think that StateChange(...) needs to return because otherwise code beyond the StateChange(...) call will be executed. This isn't how a state machine should work! For example see the implementation of event1 in the ExampleState below
import abc
class State(metaclass=abc.ABCMeta):
# =====================================================================
# == events the state optionally or must implement ====================
# =====================================================================
# optional: called when the state becomes active.
def on_state_entry(self): pass
# optional: called when we're about to transition away from this state.
def on_state_exit(self): pass
#abc.abstractmethod
def event1(self,x,y,z): pass
#abc.abstractmethod
def event2(self,a,b): pass
#abc.abstractmethod
def event3(self): pass
# =====================================================================
# == actions the state may invoke =====================================
# =====================================================================
def some_action_1(self,c,d,e):
# implementation omitted for brevity
pass
def some_action_2(self,f):
# implementation omitted for brevity
pass
class StateChange:
def __init__(self,new_state_type):
# implementation omitted for brevity
pass
class StateMachineComplete: pass
class ExampleState(State):
def on_state_entry(self):
some_action_1("foo","bar","baz")
def event1(self,x,y,z):
if x == "asdf":
return StateChange(ExampleState2)
else:
return StateChange(ExampleState3)
print("I think it would be confusing if we ever got here. Therefore the StateChange calls above are return")
def event2(self,a,b):
if a == "asdf":
return StateMachineComplete()
print("As with the event above, the return above makes it clear that we'll never get here.")
def event3(self):
# Notice that we're not leaving the state. Therefore this can just be a method call, nothing need be returned.
self.some_action_1("x","y","z")
# In fact we might need to do a few things here. Therefore a return call again doesn't make sense.
self.some_action_2("z")
# Notice we don't implement on_state_exit(). This state doesn't care about that.
When I need a state machine in Python, I store it as a dictionary of functions. The indices into the dictionary are the current states, and the functions do what they need to and return the next state (which may be the same state) and outputs. Turning the crank on the machine is simply:
state, outputs = machine_states[state](inputs)
By putting the outgoing state changes in code you're obfuscating the whole process. A state machine should be driven by a simple set of tables. One axis is the current state, and the other is the possible events. You have two or three tables:
The "next-state" table that determines the exit state
The "action" table that determines what action to take
The "read" table that determines whether you stay on the current input event or move on to the next.
The third table may or may not be needed depending on the complexity of the input "grammar".
There are more esoteric variations, but I've never found a need for more than this.
I also struggled to find a good state_machine solution in python. So I wrote state_machine
It works like the following
#acts_as_state_machine
class Person():
name = 'Billy'
sleeping = State(initial=True)
running = State()
cleaning = State()
run = Event(from_states=sleeping, to_state=running)
cleanup = Event(from_states=running, to_state=cleaning)
sleep = Event(from_states=(running, cleaning), to_state=sleeping)
#before('sleep')
def do_one_thing(self):
print "{} is sleepy".format(self.name)
#before('sleep')
def do_another_thing(self):
print "{} is REALLY sleepy".format(self.name)
#after('sleep')
def snore(self):
print "Zzzzzzzzzzzz"
#after('sleep')
def big_snore(self):
print "Zzzzzzzzzzzzzzzzzzzzzz"
person = Person()
print person.current_state == person.sleeping # True
print person.is_sleeping # True
print person.is_running # False
person.run()
print person.is_running # True
person.sleep()
# Billy is sleepy
# Billy is REALLY sleepy
# Zzzzzzzzzzzz
# Zzzzzzzzzzzzzzzzzzzzzz
print person.is_sleeping # True