Using a dict to call functions from a string - python

I would like the first two words of a user input string to be read as function arguments for where to save the string. I've settled on using a dict instead of many if statements, but I'm not sure how to structure the dict.
I believe this is a correct start:
input: "question physics What happens to atoms when they are hit by photons?"
result: program saves the input in location questions\physics
raw_entry = input("Enter text in the following format: type subtype text")
instructions = raw_entry.split()[:2]
The two words (each being a "get_id" in the example) will designate where to save the text. This example seems to be what I'm looking for, but I'm not sure how to change it for my case.
function_dict = {'get_id':
(
# function
requests.get,
# tuple of arguments
(url + "/users/" + user,),
# dict of keyword args
{'headers': self.headers}
)
}
Let me know if I'm going about this logically or if it doesn't make sense. Thanks!

You will need to define the functions separately from the dictionary
For example:
def get_id():
... the function's code ...
function_dict = { "get_id":get_id, ... }
you can then call the function with its keyword:
function_dict["get_id"]()
but you can also do this without a dictionary if the keyword is the same as the function name:
globals()["get_id"]()

Related

Conditionally modify multiple variables

Not quite sure what the correct title should be.
I have a function with 2 inputs def color_matching(color_old, color_new). This function should check the strings in both arguments and assign either a new string if there is a hit.
def color_matching(color_old, color_new):
if ('<color: none' in color_old):
color_old = "NoHighlightColor"
elif ('<color: none' in color_new):
color_new = "NoHighlightColor"
And so forth. The problem is that each of the arguments can be matched to 1 of 14 different categories ("NoHighlightColor" being one of them). I'm sure there is a better way to do this than repeating the if statement 28 times for each mapping but I'm drawing a blank.
You can at first parse your input arguments, if for example it's something like that:
old_color='<color: none attr:ham>'
you can parse it to get only the value of the relevant attribute you need:
_old_color=old_color.split(':')[1].split()[0]
That way _old_color='none'
Then you can use a dictionary where {'none':'NoHighlightColor'}, lets call it colors_dict
old_color=colors_dict.get(_old_color, old_color)
That way if _old_color exists as a key in the dictionary old_color will get the value of that key, otherwise, old_color will remain unchanged
So your final code should look similar to this:
def color_matching(color_old, color_new):
""" Assuming you've predefined colros_dict """
# Parsing to get both colors
_old_color=old_color.split(':')[1].split()[0]
_new_color=new_color.split(':')[1].split()[0]
# Checking if the first one is a hit
_result_color = colors_dict.get(_old_color, None)
# If it was a hit (not None) then assign it to the first argument
if _result_color:
color_old = _result_color
else:
color_new = colors_dict.get(_color_new, color_new)
You can replace conditionals with a data structure:
def match(color):
matches = {'<color: none': 'NoHighlightColor', ... }
for substring, ret in matches.iteritems():
if substring in color:
return ret
But you seems to have a problem that requires a proper parser for the format you are trying to recognize.
You might build one from simple string operations like "<color:none jaja:a>".split(':')
You could maybe hack one with a massive regex.
Or use a powerful parser generated by a library like this one

string formatting issue when using dictionary value

I have a weird problem when trying create a string when using a dictionary value. Basically, I have a function that opens a file, reads a line, and stores the values it finds in that line in a dictionary. Then, it sends those values to an external program. Here is the code:
def createLandscapes(file):
landscapeParameters = {'FILE': "NULL",
'N': "NULL",
'K': "NULL",
'NUM': "100"}
for line in file:
if line == "END LANDSCAPES\n":
break
else:
parameters = line.replace(" ", '').split(",")
for parameter in parameters:
parameter = parameter.split("=")
if parameter[0] not in landscapeParameters:
malformedFile()
landscapeParameters[parameter[0]] = parameter[1]
for key in landscapeParameters:
if landscapeParameters[key] == "NULL":
malformedFile()
# This print statment is for diagnostic purposes
print("./generateScoreTables {} {} {} {}".format(landscapeParameters['FILE'],
landscapeParameters['N'],
landscapeParameters['K'],
landscapeParameters['NUM']))
os.system("./generateScoreTables {} {} {} {}".format(landscapeParameters['FILE'],
landscapeParameters['N'],
landscapeParameters['K'],
landscapeParameters['NUM']))
To make this very clear, the function looks for a series of parameter inputs on a single, comma separated line, in the form of
FILE=example, N=20, K=5, NUM=100
It takes those inputs and overrides the default inputs (if specified) in landscapeParameters, and uses the values in landscapeParameters to call an external program.
The strange this is that the string formatting doesn't seem to work correctly when I use the default parameters in landscapeParameters. What I mean by this is that if the function reads the line:
FILE=example, N=20, K=5, NUM=100
Everything works correctly, and the print statement prints:
./generateScoreTables example 20 5 100
However, if the function reads the line:
FILE=example, N=20, K=5
Where I've left NUM out to use the default parameter, I get the following output instead:
./generateScoreTables testland1 15
0 100
Segmentation fault
sh: 2: 0: not found
It appears that format is not formatting this string correctly, but I don't understand why. Does anyone have any insight into this?
The problem has already been pointed out to you, but I'm still unable to comment so I'll leave this separate. This would involve reworking your code a little bit.
Once you get to this stage:
parameters = ['FILE=example', 'N=20', 'K=5', 'NUM=100']
# make a list of tuples with [(FILE, default), ('N', 20)...]
pars = [x.split("=") for x in parameters]
Now convert each twople into a Key, value pair in a dictionary dict_of_pars
dict_of_pars = {k: v for k, v in pars}
#dictionary with values for a single line
# {'FILE': 'example', 'N': '20', 'K': '5', 'NUM': '100'}
At this point you will have a dictionary containing all defined parameters for any particular line. If you make a function (that outputs) that holds default values you can send the available arguments for a line using **dict_of_pars in the call
# define output function with default parameters
def output(FILE='example, N='n', K='k', NUM='num'):
os.system(FILE, N, K, NUM)
Now you can call the function using
output(**dict_of_pars) #will unpack the arguments into output function
Made one of these temporary dictionaries for each line in the file, pass it to the output. Hope this helps.
You're updating the same variable on every loop, so if it reads one line that doesn't have a particular field it will use the value from the last time it read it.
Instead declare an empty dictionary inside the loop and use the .get function to have a default value if the key doesn't exist in the dictionary.
def createLandscapes(file):
params = ['FILE','N','K','NUM']
for line in file:
if line == "END LANDSCAPES\n":
break
else:
landscapeParameters = {}
parameters = line.replace(" ", '').split(",")
for parameter in parameters:
parameter = parameter.split("=")
if parameter[0] not in params:
malformedFile()
landscapeParameters[parameter[0]] = parameter[1]
for key in landscapeParameters:
if landscapeParameters[key] == "NULL":
malformedFile()
os.system("./generateScoreTables {} {} {} {}".format(landscapeParameters.get('FILE',''),
landscapeParameters.get('N',''),
landscapeParameters.get('K',''),
landscapeParameters.get('NUM',100)))
You'll probably need to tweak this a little bit, but it should give you more predictable results.

Call functions from string concatenations in for loop [Python]

I have a few lines that add results from functions to a list. I'm trying to turn it into a loop rather then continuous lines of assignments and append's.
so far i have the code how I want it, I'm just struggling to turn the actual string into calls to functions. I've read the pocket python guide and various other python books yet am unable to find the solution.
categories = ['Hours', 'Travel', 'Site', 'Date']
indexloc == 0
for i in categories:
func = 'v'+categories[indexloc]+' = Get'+categories[indexloc]
indexloc += 1
The results that i get are spot on im just unsure how to translate them into function calls:
>>>
vHours = GetHours
vTravel = GetTravel
vSite = GetSite
vDate = GetDate
>>>
(Just to clarify the Get parts are the function calls)
I've read
Calling a function of a module from a string with the function's name in Python
but im failing to see if/how it applies to my situation
Python 2.7
razcrasp#gmail.com
Thanks
To call a function, you need to have some reference to it. Since you know the name of the function, you can get it from the local variables:
for category in categories:
function = locals()['Get' + category]
print 'v{} = {}'.format(category, function())
A better way to do this would be to map your category names to functions:
category_mapping = {
'hours': GetHours, # CamelCase is usually for classes, not functions
'travel': GetTravel,
...
}
for category, function in category_mapping.items():
print 'v{} = {}'.format(category.capitalize(), function())

Choose list which is returned by def

I have a definition to separate some coordinates on specific properties.
For this separation I use 1 definition and within the definition i have 9 lists (different criteria's). Now for the output i just want the list defined by me. Otherwise I cannot use it for plotting.
def sorteerCord(cord):
tweestijging=[]
stijginggelijk=[]
stijgingdaling=[]
tweedaling=[]
dalinggelijk=[]
dalingstijging=[]
tweegelijk=[]
gelijkstijging=[]
gelijkdaling=[]
y=0
while y<len(cord):
lijst=cord[y]
if (lijst[1]-lijst[0])>0.5:
if (lijst[2]-lijst[1])>0.5:
tweestijging.append(y)
if (lijst[2]-lijst[1])<=0.5 and (lijst[2]-lijst[1])>=-0.5:
stijginggelijk.append(y)
if (lijst[2]-lijst[1])<-0.5:
stijgingdaling.append(y)
if (lijst[1]-lijst[0])<-0.5:
if (lijst[2]-lijst[1])>0.5:
dalingstijging.append(y)
if (lijst[2]-lijst[1])<=0.5 and (lijst[2]-lijst[1])>=-0.5:
dalinggelijk.append(y)
if (lijst[2]-lijst[1])<-0.5:
tweedaling.append(y)
if (lijst[1]-lijst[0])<=0.5 and (lijst[1]-lijst[0])>=-0.5:
if (lijst[2]-lijst[1])>0.5:
gelijkstijging.append(y)
if (lijst[2]-lijst[1])<=0.5 and (lijst[2]-lijst[1])>=-0.5:
tweegelijk.append(y)
if (lijst[2]-lijst[1])<-0.5:
gelijkdaling.append(y)
y=y+1
print raw_input()
return raw_input()
Is their a way to define in my def what the output file is like (def sorteerdCord(cord,outpu=tweestijging)
I am guessing that in the last two lines you want the user to input what output list to use but am not quite sure. You could use dictionary to map input strings to variables.
Something like:
def sorteerCord(cord, output):
# all of your separation code
outputmap = { 'tweestijging': tweestijging,
'gelijkstijging' : gelijkstijging,
# and more of those
}
return outputmap[ output ]
And then call:
sorteerCord(cord, 'gelijkstijging')
You could of course also opt for returning all of the lists or keep them in a dictionary instead:
output = { 'tweestijging': [],
'gelijkstijging': [],
# etc
}
# code to manipulate lists goes here
return output
Then selecting one afterwards using the same technique.

Use a string to call function in Python [duplicate]

This question already has answers here:
Calling a function of a module by using its name (a string)
(18 answers)
Closed 9 years ago.
Some days ago I was searching on the net and I found an interesting article about python dictionaries. It was about using the keys in the dictionary to call a function. In that article the author has defined some functions, and then a dictionary with key exactly same as the function name. Then he could get an input parameter from user and call the same method (something like implementing case break)
After that I realised about the same thing but somehow different. I want to know how I can implement this.
If I have a function:
def fullName( name = "noName", family = "noFamily" ):
return name += family
And now if I have a string like this:
myString = "fullName( name = 'Joe', family = 'Brand' )"
Is there a way to execute this query and get a result: JoeBrand
For example something I remember is that we might give a string to exec() statement and it does it for us. But I’m not sure about this special case, and also I do not know the efficient way in Python. And also I will be so grateful to help me how to handle that functions return value, for example in my case how can I print the full name returned by that function?
This does not exactly answer your question, but maybe it helps nevertheless:
As mentioned, eval should be avoided if possible. A better way imo is to use dictionary unpacking. This is also very dynamic and less error prone.
Example:
def fullName(name = "noName", family = "noFamily"):
return name + family
functionList = {'fullName': fullName}
function = 'fullName'
parameters = {'name': 'Foo', 'family': 'Bar'}
print functionList[function](**parameters)
# prints FooBar
parameters = {'name': 'Foo'}
print functionList[function](**parameters)
# prints FoonoFamily
You could use eval():
myString = "fullName( name = 'Joe', family = 'Brand' )"
result = eval(myString)
Beware though, eval() is considered evil by many people.
I know this question is rather old, but you could do something like this:
argsdict = {'name': 'Joe', 'family': 'Brand'}
globals()['fullName'](**argsdict)
argsdict is a dictionary of argument, globals calls the function using a string, and ** expands the dictionary to a parameter list. Much cleaner than eval. The only trouble lies in splitting up the string. A (very messy) solution:
example = 'fullName(name=\'Joe\',family=\'Brand\')'
# Split at left parenthesis
funcname, argsstr = example.split('(')
# Split the parameters
argsindex = argsstr.split(',')
# Create an empty dictionary
argsdict = dict()
# Remove the closing parenthesis
# Could probably be done better with re...
argsindex[-1] = argsindex[-1].replace(')', '')
for item in argsindex:
# Separate the parameter name and value
argname, argvalue = item.split('=')
# Add it to the dictionary
argsdict.update({argname: argvalue})
# Call our function
globals()[funcname](**argsdict)

Categories