Calling code in a string without exec/eval, python
I have this code that executes when a player attempts to eat something:
def eat(target='object'):
global current_room
global locations
global inventory
if target in inventory:
items[target]['on_eat'] #This is showing no results.
else:
print 'You have no ' + target + ' to eat.'
and this code for items(trimmed)
items = {
'strawberry': {
'weight': 1,
'text': 'The strawberry is red',
'on_eat': "normal_eat('strawberry', 'pretty good, but not as sweet as you expected')"
},
'trees': {
'weight': 50,
'text': 'The trees are tall with large, leaf filled branches blocking out a majority of sunlight.',
'on_eat': "forcesay('Eating trees? What the hell is your proble开发者_开发问答m?')"
}
}
Is there a valid way of calling items[whatever]['on_eat'] without doing something silly like exec() or eval()? If not, alternative formatting as an example would also be appreciated.
Before this the items[everyitems]['on_eat'] values were not strings, but that executed the on_eat for every item as soon as the code was ran.
I have seen many answers to similar questions, but they don't deal with arguments for functions unique- to better put that, they were more like this
You can store your function and function arguments as a partial
:
from functools import partial
items = {
'strawberry': {
'weight': 1,
'text': 'The strawberry is red',
'on_eat': partial(normal_eat, 'strawberry', 'pretty good, but not as sweet as you expected')
},
'trees': {
'weight': 50,
'text': 'The trees are tall with large, leaf filled branches blocking out a majority of sunlight.',
'on_eat': partial(forcesay, 'Eating trees? What the hell is your problem?')
}
def eat(target='object'):
# those globals are probably not necessary
if target in inventory:
items[target]['on_eat']() #Add ()'s to call the partial
else:
print 'You have no ' + target + ' to eat.'
you can use the code module
def eat(target='object'):
import code
console = code.InteractiveConsole(locals()) # make a python interpreter with local vars
if target in inventory:
console.push("items[target]['on_eat']")
else:
print 'You have no ' + target + ' to eat.'
An alternative to partial functions is to write items like this
items = {
'strawberry': {
'weight': 1,
'text': 'The strawberry is red',
'on_eat': (normal_eat,('strawberry', 'pretty good, but not as sweet as you expected'))
},
'trees': {
'weight': 50,
'text': 'The trees are tall with large, leaf filled branches blocking out a majority of sunlight.',
'on_eat': (forcesay,('Eating trees? What the hell is your problem?',))
}
}
and call it like this
def eat(target='object'):
if target in inventory:
func, args = items[target]['on_eat']
func(*args)
else:
print 'You have no ' + target + ' to eat.'
You don't need those global
statements there unless you will be reassigning them
精彩评论