Pass parameters with different amount of variables to function - python

I am trying to create function that would take a random amount of parameters some defined, others not.
So I have this search function that would sometimes take all of the arguments, but sometimes just url, query and authHeader.
I did study about *arg, **kwards, but AFAIK they did not suit in this case.
Or do I always have to give them some value in my case, for example "null"? But that means I need to assign a value to variable and could not just pass it that time?
def search(url, query, resultLimit, resultInfoSize, authHeader):
searchRequest = session.post(url + '/services/search?q=' + query + '&num=' + resultLimit + '&datalinesToReturn='+ resultInfoSize, headers=authHeader)
searchData = searchRequest.json()
return searchData
Any opinion much appreciated.
Update
as #Jerrybibo kindly stated I got my aswer:
So adding if condition in the function was what I was looking for. Changing the default values inside the function if on call none are provided.
def search(url, query, resultLimit, authHeader, resultLimit=None, resultInfoSize=None):
if resultLimit == None: resultLimit='50'
if resultInfoSize == None: resultInfoSize=''
searchRequest = session.post(url + '/services/search?q=' + query + '&num=' + resultLimit + '&datalinesToReturn='+ resultInfoSize, headers=authHeader)
searchData = searchRequest.json()
return searchData

Looking at your question, I believe one way of working around this is to have several of your function parameters set to default sentinel values (usually None; use whichever default value makes sense in your scenario) so that you do not have to pass the values on function call; and if you do pass them, they get processed just like normal parameters. Your function definition would look like this:
def search(url, query, authHeader, resultLimit=None, resultInfoSize=None):
Additionally, you may have to change your searchRequest definition in the function in the event that resultLimit or resultInfoSize is None.

Related

Passing return value to function

I'm having difficulty understanding how to use return values.
def grab_name(string):
return grab("users/self/profile", string)
def print_user_info(arg):
print(grab("users/self/profile", "janice"))
I need to consume the result of passing the first function in order to print the user info. But I'm not sure how to do that...the second function is not supposed to consume a string or call the function directly. I understand the return value doesn't exist outside the scope of the first function so I don't understand how to get the value into the second function without just calling it directly as I have above.
The first function is basically returning a dictionary and the second function needs to consume the result of calling the first function.
I think this small modification is what you are seeking.
def grab_name(string):
return grab("users/self/profile", string)
def print_user_info(arg):
print(grab_name("janice"))
def grab_name(string):
return grab("users/self/profile", string)
def print_user_info(arg):
return "janice"
print(print_user_info(grab_name))
result :
janice

Defining default keyword values to function in a dictionary in python

I am writing a function that takes a lot of keywords.
I have a dictionary which is very lengthy that contains many of these keywords that already exists in my code and is being used elsewhere. E.g.
{'setting1':None, 'setting2': None....}
I am wondering is there a way, when I define my function, for me to set all of these as keywords, rather than having to type them out again like this:
def my_function(setting1=None, setting2=None, **kwargs)
To be clear, essentially I want to set all of the contents of the dictionary to be keywords with default value None, and when I call the function I should be able to change their values. So I am not looking to provide the dictionary as kwargs upon calling the function.
While not exactly the same, I ususally prefer to save the arguments in **kwargs and use .get() to get the value or None:
def my_function(**kwargs):
do_something(kwargs.get("alpha"), kwargs.get("beta"))
.get() on a dictionary returns the value if a key exists, or None of it does not. You can optionally specify a different default value as a second argument if you like.
When creating a function, you will need to implement how your arguments are used. By automatically creating arguments you end up adding arguments and forgetting to implement a behaviour for them.
# Manually defined.
def func(a, b, c, d):
return a + b / c * d
# Auto-defined - Human error.
def func(""" auto define a,b,c,d,e,f,g,h """):
return a + b / c * d # <- you only use half of the arguments. Confusing at best.
# Auto-defined - Inputs unclear, code is not explicit.
def func(defind_my_args):
return a + b / c * d
If you need to reuse "code behaviour" to the point that you can "inherit" parameters, maybe you should be using an object instead.

Using string as literal expression in function argument in Python

Let's say I have a function that can take various kinds of parameter values, but I don't want to (as a constraint) pass arguments explicitly. Instead, I want to pass them as a string.:
def func(param)
return param+param
a = 'param=4'
func(<do something to a>(a))
>>8
Is this possible in python?
I want to use this idea in Django to create Query filters based on GET parameters in a dictionary and then just chain them using their keys.
lookup_dic = {'user': 'author=user',
'draft': 'Q(publish_date_lte=timezone.now())|
Q(publish_date_isnull=True)'}
Based on whether the user and draft keywords are passed in the GET parameters, this would be read out like:
queryset.objects.filter(author=user).filter(Q(publish_date_lte=timezone.now())|
Q(publish_date_isnull=True))
I understand that I can do this by replacing the author=user by Q(author__name=user), but I wanted to know if this string comprehension feature is implemented in python in general?
Use eval
def func(param=0):
return param+param
a = 'param=4'
eval('func(' + a +')')
Are you looking for this?
def func(param):
return param + param
a = 'param=4'
parameter, value = a.split("=")
print(func(**{parameter: int(value)}))
# >> 8

Is it possible to use a function in an SQLAlchemy filter?

I have a function that checks an object for some properties and returns boolean values depending on the result. It's too complex to write it in filter, but it works and returns the right value.
Now I want to use sqlalchemy to return all objects that this function returns True for. I tried:
DBSession.query(MyObject).filter(self.check_attributes(MyObject) == True).all()
and
DBSession.query(MyObject).filter(self.check_attributes(MyObject)).all()
Both failed to select the right objects. What am I doing wrong?
As I said in my comment, hybrid_method/hybrid_property is the appropriate pattern for your use case. It may at first seem complicated, but it's actually quite simple. The first version of the function operates exactly like a Python method or property, and the second part acts as a class method. SQLAlchemy filters work on the class to generate SQL.
This is just a useless example, but instead of therabouts your example could have a complicated calculation.
If you don't need to pass any parameters then I suggest using hybrid_property instead.
class MyObject(Model):
name = Column(String)
num = Column(Integer)
#hybrid_method
def therabouts(self, n):
return self.num > n - 5 and self.num <= n + 5
#therabouts.expression
def therabouts(cls, n):
return and_(cls.num > n - 5, cls.num <= n + 5)
#hybrid_property
def is_al(self):
return self.name.lower().startswith('al')
#is_al.expression
def is_al(cls):
return cls.name.ilike('al%')
# When used as a class method #thereabouts.expression is called
near20 = session.query(MyObject).filter(MyObject.therabouts(20)).first()
# When used as an instance, #hybrid_method is called
near20.therabouts(20) # True
near20.therabouts(22) # Maybe True
near20.therabouts(50) # False
# filter example (class)
all_als = session.query(MyObject).filter(MyObject.is_al).all()
for al in all_als:
print al.name
# output Alan, Alanzo, Albert...
# instance example (self)
bob = MyObject(name='Robert')
print bob.is_al # False
If by "use a function" you mean write the filters inside a function, you certainly can - you just need to pass the correct argument to it (the query) and use its return (the filtered query) in the proper place
Let's take an example from SQLAlchemy's tutorial:
wendy = session.query(User).filter_by(name='wendy').one()
You can move the filter(s) to a function easily:
def my_filter(query):
return query.filter_by(name='wendy')
wendy = my_filter(session.query(User)).one()
However, if by " function that checks an object for some properties and returns boolean values depending on the result" you mean a function that accepts a database record as an argument, I don't think it can be done (without subverting the whole purpose of using SQL).
--EDIT-- As doog abides points out, the hybrid extension, while not operating on database records, does something that's equivalent for many practical purposes.
Of course, some people will insist in writing something like:
all_users = session.query(User).all()
wendy= filter( lambda u:u.name=='wendy', all_users )
But, for the sake of the sanity of your fellow programmers and users, please don't do that.

return variable name from outside of function, as string inside python function

So I have created a function that applies an action (in this case point wise multiplication of an array with a sinusoid, but that does not matter for my question) to an array.
Now I have created another function with which I want to create a string of python code to apply the first function multiple times later-on. The input of the second function can be either a string or an array, so that I can use the second function on its own output as well, if need be. My method of getting the variable name in a string works outside of the function.
Input :
var = np.array([[1,3],[2,4]]) # or sometimes var = 'a string'
if type(var)==str:
var_name = var
else:
var_name = [ k for k,v in locals().items() if v is var][0]
var_name
Output :
'var'
So here var is the variable (either array or string) supplied to the function, in this case an array. The if statement nicely returns me its name.
However when I use this inside my function, no matter what input I give it, it actually seems to look for var in locals(). Somehow it does not take var from the function input.
Definition :
def functionTWO(var, listoflistsofargs=None):
if type(var)==str:
var_name = var
else:
var_name = [ k for k,v in locals().items() if v is var][0]
if listoflistsofargs==None:
return var_name
command = []
for i in range(len(listoflistsofargs)):
if i==0:
command.append('functionONE(')
command.append(var_name)
command.append(',%.17f, %.17f)' % tuple(listoflistsofargs[i]))
else:
command.insert(0,'functionONE(')
command.append(',%.17f, %.17f)' % tuple(listoflistsofargs[i]))
''.join(command)
command[0] = var_name + ' + ' + command[0]
return ''.join(command)
Input :
somearray = np.array([[1,2,3],[1,2,3],[1,2,3]])
args = [[1,3],[6,5]]
command = functionTWO(somearray, args)
command
Output :
NameError: name 'var' is not defined
Wanted output :
'functionONE(functionONE(somearray, 1, 3), 6, 5)'
Why is listoflistsofargs taken from the function input and var not? I specify var in the listcomprehension in the definition of functionTWO. Normally when I use list comprehensions with function inputs it works fine. Does anybody know why this isnt the case here? Thank you in advance!
EDIT : So I guess the answer is dont. The implementation of classes by Marcin looks much cleaner and about the same order of amount of code. Too bad I couldnt get this to work inside a function. For other donts (actually other ideas) about using variable names as strings there is this question, where I got the above list comprehension for variable names.
You cannot pass a variable as a string*, and you should not do so.
If you want to pass a value between functions, the normal way is to pass it in as a parameter, and out as a return value.
If that is inconvenient, the usual solution is an object: define a class which carries both the shared variable, and methods which act on the variable.
If you need to create command objects, it is much better to do so in a structured way. For example, if you want to pass a function, and parameters, you can literally just pass the function object and the parameters in a tuple:
def foo():
return (functionONE,somearray,1,3)
command = foo()
command[0](*command[1:])
If you want to embed such commands within commands, you'll likely want to wrap that up with a class, so you can recursively evaluate the parameters. In fact, here's a little evaluator:
def evaluator(object):
def __init__(self,func=None,params=None):
self.func = func
self.params = params
def eval(self,alternativeparams=None):
if alternativeparams is not None:
params = alternativeparams
else:
params = self.params
if params is not None:
evaluatedparams = (item() if callable(item) else item for item in params)
else: evaluatedparams = None
if func is not None:
return self.func(*(evaluatedparams or ()))
else: return evaluatedparams
def __call__(self, *params):
return self.eval(params if params else None)
Although there are hacks by which you can pass references to local variables out of a function, these are not a great idea, because you end up creating your own half-baked object system which is more difficult to understand.
* This is because a variable has a name (which is a string) and a context, which maps names to strings. So, you need, at least to pass a tuple to truly pass a variable.
presenter's answer works in python 3
def get_variable_name(*variable):
return [ k for k,v in globals().items() if v is variable[0]][0]
example:
>> test = 'sample string'
>> get_variable_name(test)
'test'
>>
The only issue is it is a little messy.
The reason you get the error NameError: name 'var' is not defined when you wrap it all into a function is the following: locals().items() refers to the locally defined variables. as a matter of fact, the locally defined variables in your functions are only the variables defined inside the function and those passed as arguments to the function.
As the name says, locals().items() is local, and will consist of different variables depending on where it is called in your script.
On the contrary globals().items() consists of all the global variables, so try using it instead in your functions, it should do the trick.
For more info, look up global and local variables as well as the scope of variables in Python.

Categories