Use a string to call function in Python [duplicate] - python

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)

Related

Using a dict to call functions from a string

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"]()

define a dict of variables in a for loop : hello = var('hello')

var = {'hello': 'world', 'good': 'day', 'see': 'you'}
Function:
def func(key):
return newfunc(var[key])
I would like to get something like this: hello = func('hello') = newfunc('world').
varlist = list(var.keys())
for i, variab in enumerate(varlist):
varname = variab
variab = func(varname)
But the problem at last the variables are not defined because the variable variab is overwritten when the next iteration starts. So do I have other ways to code a for loop to define all the variables in the dict?
I know I can keep writing hello = func('hello') and other variables every line but I would like to know if another method is possible.
You may find this article to be a worthwhile read: http://stupidpythonideas.blogspot.com/2013/05/why-you-dont-want-to-dynamically-create.html/
The short answer to the problem is that when you do:
variab = func(varname)
You aren't defining a new variable, you are just defining the value stored in the variable. Variab is static. The name isnt changing. To define a static variable, you use the syntax
globlas()[variablename] = variablevalue
And while this is possible, it begs the question of why? There is pretty much no need to create variables dynamically in this way, and there's a reason why you don't generally see this pattern in programming. The solution? Use a data structure to solve the problem properly.
The article suggests dictionaries, but depending on your data structure you can use classes as well. It depends on the problem you are trying to accomplish.
If you must use dynamically created global variables I would strongly recommend getting past the new to Python stage before doing so. Again, the current code patterns and data structures exist for a reason, and I would discourage willingly avoiding them in favor of a workaround style solution.
Dynamically creating variables can be done, but it is not wise. Maintenance is a nightmare. It would be better to store the functions in a dictionary with the key value being what the dynamically created variable would have been. This should give you an idea of how it can be done:
#!/usr/bin/python
h = {'hello': 'world', 'good': 'day', 'see': 'you' }
def func(v):
def newfunc():
return v
return newfunc
for k,v in h.items():
h[k] = func(v)
a = h['hello']()
b = h['good']()
c = h['see']()
print("a = {}".format(a))
print("b = {}".format(b))
print("c = {}".format(c))
First of all, are those values callable functions or just string values?
If they are some callable functions, something like:
a = {'hello': hello, 'world': world}
It is simple and straight forward:
A = {'hello': hello, 'world': world}
def foo(var):
callback = A.get(var, None)
# You cancheck and raise when the value
# is not a method.
if not callable(callback):
raise
return callback
foo('hello')
You can put the variable, fn pairs in a dict.
Also some comments:
you don't use the index i in the for loop so there is no point in using enumerate.
there is no point renaming variab to varname. If you want to use this name then just use it from the beginning.
you can iterate the dict_keys so there is no need for the varlist = list(var.keys()) line, you can just use for variab in var.keys()...
... actually you don't even need the var.keys(). for key in dictionary iterates through the keys of the dictionary, so you can just use for variab in var.
So something like this would work:
fn_dict = {}
for varname in var:
fn_dict[varname] = func(varname)
At the end of the loop you will have the fn_dict populated with the key, function pairs you want.

Converting list of variables to strings [duplicate]

This question already has answers here:
How do I create variable variables?
(17 answers)
Closed 5 years ago.
I have a list of commands that I want to iterate over so I've put those commands into a list. However, I want to also use that list as strings to name some files. How do I convert variable names to strings?
itemIDScore = """SELECT * from anytime;"""
queryList = [itemIDScore, accountScore, itemWithIssue, itemsPerService]
for x in queryList:
fileName = x+".txt"
cur.execute(x) #This should execute the SQL command
print fileName #This should return "itemIDScore.txt"
I want fileName to be "itemIDScore.txt" but itemIDScore in queryList is a SQL query that I'll use elsewhere. I need to name files after the name of the query.
Thanks!
I don't think you may get name of the variable as string from the variable object. But instead, you may create the list of string of your variables as:
queryList = ['itemIDScore', 'accountScore', 'itemWithIssue', 'itemsPerService']
Then you may access the value of variable from the variable name string using the globals() function as:
for x in queryList:
fileName = "{}.txt".format(x)
data = globals()[x]
cur.execute(data)
As the globals() document say:
Return a dictionary representing the current global symbol table. This is always the dictionary of the current module (inside a function or method, this is the module where it is defined, not the module from which it is called).
As far as I know, there is no easy way to do that, but you could simply use a dict with what currently are variable names as keys, e.g.:
queries = {
'itemIDScore': 'sql 1',
'accountScore': 'sql 2',
...
}
for x in queries:
fileName = x + ".txt"
cur.execute(queries[x])
print fileName
This would also preserve your desired semantics without making the code less readable.
I think you would have an easier time storing the names explicitly, then evaluating them to get their values. For example, consider something like:
itemIDScore = "some-long-query-here"
# etc.
queryDict = dict( (name,eval(name)) for name in ['itemIDScore', 'accountScore', 'itemWithIssue', 'itemsPerService'] )
for k in queryDict:
fileName = k+".txt"
cur.execute(queryDict[k])
You can use the in-built str() function.
for x in queryList:
fileName = str(x) + ".txt"
cur.execute(x)

how to rid "" from a string to non string

I have this
a = "'Something': False"
I want it to be this
a = 'Something': False
How do I do it? I can strip things within the double quotation marks, but not the quotation marks itself. Have researched, cant find. I have mind block at moment. Sorry
Im trying to do this:
query_results = UserProfile.objects.filter(Location: location, Gender: gender).extra(select={'rank': a > 0}, order_by=['-rank'])
where Location = Someplace and Gender = Male or Female.
But what about when i did not want a specific gender or location. The only thing i could think of to do was to do
Location__isnull:False, Gender__isnull:False
But i cant have both
Location:location, Location__isnull:False.
Thus i have to have the location argument as a variable.
How could i then do this. The information referring to Location and gender is coming from a request.GET
I cant post my code as i keep deleting and changing spaghetti to try make something edible.
For what you're trying to do, the easiest way is to build up a dictionary of the arguments you want to supply, then pass them to the filter() call. Here's some non-working sample code that might get you heading in the right direction.
arguments = {}
if location is not None:
arguments['Location'] = location
else:
arguments['Location__isnull'] = False
if gender is not None:
arguments['Gender'] = gender
else:
arguments['Gender__isnull'] = False
query_results = UserProfile.objects.filter(**arguments)
It's not clear from your question whether or not you really need to search these for records which are not null. An empty .filter() would return all the records just as if you'd called .all(), and if you use the pattern I've suggested, you could omit all the else clauses and just feed filter(**arguments) an empty dictionary.
In other words, you only need to specify the query terms you really require, and do that by adding them to the arguments dictionary. Then you call filter with **arguments. The ** is a special Python syntax that says "take all the key/value pairs in this dictionary and turn them into keyword arguments for this function."
You can't. This is not valid python syntax: 'Something': False ... unless it's inside a dictionary: {'Something': False}. And no, you can not assign 'Something': False to a variable.
stufftofilter = {}
if shouldFilterLocation:
stufftofilter['Location'] = 'thelocation'
# etc
query_set = UserProfile.objects.extra(select={'rank':a>0}, order_by=['-rank'])
if stufftofilter:
query_set.filter(**stufftofilter)

Variable interpolation in Python [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Unpythonic way of printing variables in Python?
In PHP one can write:
$fruit = 'Pear';
print("Hey, $fruit!");
But in Python it's:
fruit = 'Pear'
print("Hey, {0}!".format(fruit))
Is there a way for me to interpolate variables in strings instead? And if not, how is this more pythonic?
Bonus points for anyone who gets the reference
The closest you can get to the PHP behaviour is and still maintaining your Python-zen is:
print "Hey", fruit, "!"
print will insert spaces at every comma.
The more common Python idiom is:
print "Hey %s!" % fruit
If you have tons of arguments and want to name them, you can use a dict:
print "Hey %(crowd)s! Would you like some %(fruit)s?" % { 'crowd': 'World', 'fruit': 'Pear' }
The way you're doing it now is a pythonic way to do it. You can also use the locals dictionary. Like so:
>>> fruit = 'Pear'
>>> print("Hey, {fruit}".format(**locals()))
Hey, Pear
Now that doesn't look very pythonic, but it's the only way to achieve the same affect you have in your PHP formatting. I'd just stick to the way you're doing it.
A slight adaptation from the NamespaceFormatter example in PEP-3101:
import string
class NamespaceFormatter(string.Formatter):
def __init__(self, namespace={}):
super(NamespaceFormatter, self).__init__()
self.namespace = namespace
def get_value(self, key, args, kwds):
if isinstance(key, str):
try:
# Check explicitly passed arguments first
return kwds[key]
except KeyError:
return self.namespace[key]
else:
super(NamespaceFormatter, self).get_value(key, args, kwds)
fmt = NamespaceFormatter(globals())
fruit = 'Pear'
print fmt.format('Hey, {fruit}!')
for:
Hey, Pear!
Something like this should work:
"%(fruit)s" % locals()
Don't do it. It is unpythonic. As example, when you add translations to your app, you can't longer control which variables are used unless you check all the translations files yourself.
As example, if you change a local variable, you'll have to change it in all translated strings too.

Categories