How to call a fucntion from a dict variable
Hello i am sorry for such a question but i am learning python and i am using the book named [Learn python the hard way]. On exercise 43_Classes.py i cannot figure out why my output is giving my invalid syntax i was hoping someone on here could point out what is going wrong in this script thank you.
from sys import exit from random import randint class Scene(object): def enter(self): pass class Engine(object): def __init__(self, scene_map): self.scene_map = scene_map def play(self): current_scene = self.scene_map.opening_scene() while True: print "\n--------" next_scene_name = current_scene.enter() current_scene = self.scene_map.next_scene(next_scene_name) class Death(Scene): quips = [ "You dies. You kinda suck at this.", "Your mum would be proud. if she were smarter.", "Such a loser!", "I have a small puppy that would be better at this than you.", "Wasted Non-GTA (ref).", "Gothon's rule!" ] def enter(self): print Death.quips[randint(0, len(self.quips)-1)] exit(1) class CentralCorridor(Scene): def enter(self): print "The Gothons of planet percal #25 have invaded your ship and destroyed" print "your entire crew. You are the last surviving member and you last" print "mission is to get the neutron destruct bomb from the weapons armory." print "put it in the bridge, and blow the ship up after getting into an " print "escape pod." print "\n" print "You're running down the central corridor to the weapons armory when" print "a Gothon jumps out, red scaly skin, dark grimy teeth, and evil clown costume" print "flowing around his hate filled body. He's blocking the door to the" print "Armory and about to pull a weapon to blast you." action = raw_input("> ") if action == "shoot!": print "Quick on the draw you yank out your blaster and fire it at the Gothon." print "His clown costume is flowing and moving around his body, which throws" print "off your aim. Your laser hit his costume but misses him entirely. This" print "completely ruins his brand new costume his mother bought him, which" print "makes him fly into a rage and blast you repeatedly in the face until" print "you are dead. Then he eats you." return 'death' elif action == 'dodge!': print "Like a world class boxer you dodge, weave, slip and slide right" print "as the Gothon's blaster cranks a laser past your head." print "In the middle of your artful dodge your foot slips and you" print "bang your head on the wall and pass out." print "you wake up shortly after only to die as the Gothon stomps on" print "your head and eats you." return 'death' elif action == 'tell a joke' or 'cheat': print "Lucky for you they made you learn Gothon insults in the academy." print "You tell the Gothon a joke you know: " print "Lbhe zbgure vf fb sng, jura fur fvgf nebhaq gur ubhfr, fur fvgf nebhaq gur ubhfr." print "The Gothon stops, tries not to laugh, then bust out laughing and can't move." print "While he's laughing you run up and shoot him square in the head" print "putting him down, then jump through the Weapon Armory door." return 'laser_weapon_armory' else: print "DOES NOT COMPUTE!" return 'central_corridor' class LaserWeaponArmory(Scene): def enter(self): print "You do a dive roll into the Weapon Armory, crouch and scan the room" print "for more Gothons that might be hidding. It's dead quiet, too quiet." print "You stand up and run to the far side of the room and find the" print "neutron bomb in its container. There's a keypad lock on the box" print "and you need the code th get the bomb out. If you get the code" print "wrong 10 times then the lock closes forever and you can't" print "get the bomb. The code is 3 digits." print "Deactivate my bomb c**t!" code = "%d%d%d" % (randint(1,9), randint(1,9), randint(1,9)) guess = raw_input("Python call function dict> ") guesses = 0 attempts = 10 while guess != code and guesses < 9: guesses += 1 attempts -= 1 cheat = 000 print "Invaid key!\nAttempts left (%d)" % attempts guess = raw_input("Python call function dict>") guess_01 = guess if guess == code or guess_01 : print "the container clicks open and the seal breaks, letting gas out." print "You grab the neutron bomb and run as fast as you can to the" print "bridge where you must place it in the right spot." return 'the_bridge' elif guess != code and guesses < 9: pass else: print "The lock buzzes one last time and then you hear a sickening" print "melting sound as he mechanism is fused together." print "You decide to sit there, and finally the Gothons blow up the" print "ship from their ship and you die." return 'death' class TheBridge(Scene): def enter(self): print "You burst onto the Bridge with the neutron destruct bomb" print "under your arm and suprise 5 Gothons who are trying to" print "take control of the ship. Each of them has an even uglier" print "clown costume than the last. They haven't pulled their" print "weapons out yet, as they see the active bomb under your" print "arm and don't want to set it off." action = raw_input(">") if action == "throw the bomb": print "The bomb explodes!" return 'death' elif action == 'slowly place the bomb' or 'cheat': print "You run to the escape pods" print "and leave the bomb behind. " return 'escape_pod' else: print "This does not compute!" return 'death' class EscapePod(Scene): def enter(self): print "There are 5 pods which one?" good_pod = randint(1, 5) guess = raw_input("> ") if int(guess) != good_pod: print "You jump into pod number: %s" % guess print "You are stuck the pod wont open your stuck inside!" return 'death' else: print "Yay you shoot out and the ship blows up you win!" return 'finished' class Map(object): scenes = < "central_corridor": CentralCorridor(), "laser_weapon_armory": LaserWeaponArmory(), "the_bridge": TheBridge(), "escape_pod": EscapePod(), "death": Death() >def __init__(self, start_scene): self.start_scene = start_scene def next_scene(self, scene_name): return Map.scenes.get(scene_name) def opening_scene(self): return self.next_scene(self.start_scene) a_map = Map('central_corridor') a_game = Engine(a_map) a_game.play()
How to call a function inside a dictionary in python
I am creating a python shell script that will allow the user to enter commands that output a string. But also some commands will call a function, like help, or exit I know python does not have a switch case so I am using a dictionary instead, as I do not want to use if and else statements The problem: The problem is I cannot use a function call inside the dictionary with the way I have it implemented as it expects to output a string, so when I enter help I get an error
#!/usr/bin/python x = 0 while x == 0: def helpCommand(): print "this will help you" switcher = < "url": " the url is: . ", "email": " my email is: . ", "help": helpCommand, "exit": exit, >choice = raw_input("enter your command choice: ") def outputChoice(choice) return switcher.get(choice) print outputChoice(choice)
I tried to solve this problem by using function call instead, but now I get an error when trying to call a string
def outputChoice(choice) return switcher[choice]()
If it’s a string, you can’t «call» it. If it’s a function, you must call it. You’ll need an if..else to figure out which to do.
I’d just make all the values in switcher functions. Then just call them. They can all take the same arguments (if any). If you really want to have strings as well as functions, you can always check the type and handle strings separately, but I don’t think that buys you much.
Passing a dictionary to a function as keyword parameters
I’d like to call a function in python using a dictionary with matching key-value pairs for the parameters. Here is some code:
d = dict(param='test') def f(param): print(param) f(d)
d = dict(p1=1, p2=2) def f2(p1, p2): print(p1, p2) f2(d)
Is it possible to write function in the general form such as «def f(**dic):» to get any number of key-value pairs?
4 Answers 4
Figured it out for myself in the end. It is simple, I was just missing the ** operator to unpack the dictionary
d = dict(p1=1, p2=2) def f2(p1,p2): print(p1, p2) f2(**d)
if you’d want this to help others, you should rephrase your question: the problem wasn’t passing a dictionary, what you wanted was turning a dict into keyword parameters
This is great, just used it with argparse/__dict__ to make it really easy to do command line argument parsing directly into options for a class object.
what is the reason we would want to unpack a dictionary when passing it as an argument to a function?
In[1]: def myfunc(a=1, b=2): In[2]: print(a, b) In[3]: mydict = In[4]: myfunc(**mydict) 100 200
A few extra details that might be helpful to know (questions I had after reading this and went and tested):
- The function can have parameters that are not included in the dictionary
- You can not override a function parameter that is already in the dictionary
- The dictionary can not have values that aren’t in the function.
Number 1: The function can have parameters that are not included in the dictionary
In[5]: mydict = In[6]: myfunc(**mydict) 100 2
Number 2: You can not override a function parameter that is already in the dictionary
In[7]: mydict = In[8]: myfunc(a=3, **mydict) TypeError: myfunc() got multiple values for keyword argument 'a'
Number 3: The dictionary can not have values that aren’t in the function.
In[9]: mydict = In[10]: myfunc(**mydict) TypeError: myfunc() got an unexpected keyword argument 'c'
How to use a dictionary with more keys than function arguments:
A solution to #3, above, is to accept (and ignore) additional kwargs in your function (note, by convention _ is a variable name used for something being discarded, though technically it’s just a valid variable name to Python):
In[11]: def myfunc2(a=None, **_): In[12]: print(a) In[13]: mydict = In[14]: myfunc2(**mydict) 100
Another option is to filter the dictionary based on the keyword arguments available in the function:
In[15]: import inspect In[16]: mydict = In[17]: filtered_mydict = In[18]: myfunc(**filtered_mydict) 100 200
Example with both positional and keyword arguments:
Notice further than you can use positional arguments and lists or tuples in effectively the same way as kwargs, here’s a more advanced example incorporating both positional and keyword args:
In[19]: def myfunc3(a, *posargs, b=2, **kwargs): In[20]: print(a, b) In[21]: print(posargs) In[22]: print(kwargs) In[23]: mylist = [10, 20, 30] In[24]: mydict = In[25]: myfunc3(*mylist, **mydict) 10 200 (20, 30)
How to pass members of a dict to a function
Now I want to call this function passing elements from a dict that contains keys that are identical to the arguments of this function. I could do something like:
some_func(foo=mydict['foo'], bar=mydict['bar'], bas=mydict['bas'], baz=mydict['baz'])
Is there some elegant way I could take advantage of the fact that the keys match the parms to do this less verbosely? I know I could pass the whole dict, but let’s say I either don’t want to or can’t change the function to accept a single dict rather than the individual arguments. Thanks, Jerry
2 Answers 2
That’s what ** argument unpacking is for:
See also Unpacking argument lists in the Python tutorial.
It works if the function accepts keyword args using the ** notation, in which case it will get the extra ones as a separate dictionary and probably ignore them. Otherwise no.
if you want to pass an unknown number of arguments, you can give your function a **kwargs parameter. saltycrane.com/blog/2008/01/…
I was about 98% sure it wouldn’t work, but I admit I’ve never used the feature. This question shows how to pare the dict down to the valid subset: stackoverflow.com/questions/4194365/…
As Sven notes, you can pass a dict to a function using ** unpacking. But if the dict contains keys that aren’t argument names to the target function, this works only if the function you’re calling accepts keyword arguments using the ** notation. If it doesn’t, you’ll get an error.
If the function you’re calling doesn’t have a **kwargs parameter, the easiest way to handle it is to add one. But if you can’t do that, you have a couple approaches:
1) Write a wrapper function:
def wrapper(foo, bar, baz, quux, **kwargs): return some_func(foo, bar, baz, quux) wrapper(**mydict)
2) Write a function to extract just the dict keys you need:
def extract(dikt, keys): return dict((k, dikt[k]) for k in keys.split()) some_func(**extract(mydict, "foo bar baz quux"))
3) Write a function that introspects the function you’re calling and extracts the keys you need from the dictionary — basically the same as #2 except you don’t have to «repeat yourself» as much.
def call_with_dict(func, dikt): func(**dict((k, dikt[k]) for k in func.func_code.co_varnames[:func.func_code.co_argcount])) call_with_dict(some_func, my_dict)
Note that this doesn’t allow you to omit arguments that have default values in the function signature. You could do some additional introspection to permit that (the length of func.func_defaults determines which of the arguments have default values).
This introspection is for Python 2.x, Python 3 and later will probably need some tweaking. For this reason, I prefer one of the first two methods.
PS — Thanks to Sven for catching my missing ** in my second approach.