Passing default values to **kwargs - python

I have a function that returns some data, what I need to do in order to get the data is to pass an SQL-like query to the build_query variable.
def foo(client):
"""
API service that returns JSON data and accepts arguments
"""
report_query = (client.buildQuery()
.Select('Date','SearchEngine')
.From('Report_10')
.During('Yesterday')
get_report.downloadReport(
skip_header=True,
include_names=False,
get_summary=True,
get_totals=False)
What I am trying to do is make this function in to one that accepts **kwargs but has default arguments for the selected fields.
The idea is that I would be able to pass an argument to .During() and if I don't it defaults to Yesterday, I would be able to pass arguments to .Select(), for example .Select() would be .Select('Date','Device','StrategyType').
What I've tried and trying to understand:
def fn(**kwargs):
print(f"""
({kwargs['client']}.buildQuery()
.Select({kwargs['select']}))
.From({kwargs['report_type']})
.During({kwargs['during']})
get_report.downloadReport(
skip_header={kwargs['skip_header']},
include_names={kwargs['include_names']},
get_summary={kwargs['get_summary']},
get_totals={kwargs['get_totals']})""")
fn(client='10',select=['Date', 'SearchEngine'],report_type='new',during='Yesterday',skip_header=True)
Returns:
(10.buildQuery()
.Select(['Date', 'SearchEngine']))
.From(new)
.During(Yesterday)
get_report.downloadReport(
skip_header=True,
include_names=False,
get_summary=True,
get_totals=False)
Where I get stuck is trying to call fn() without any keyword arguments and wishing that the function would have default arguments for each field, such that it would look like the first code snippet in my question.
fn()
KeyError: 'client'
Is it possible to achieve something like this?

You can use the spread operator on dictionaries:
def func(**kwargs):
kwargs = {"printer": None, **kwargs}
This will set the value printer to none if it is not given.

Related

What does None in a function mean / optional fields

I am trying to use the function below. Mostly when i call this function I just pass in the report_type but a few of the report calls wants a start_date. Questions
Does the None in the definition of function mean that the field is optional
def request_report(self, report_type, start_date=None, end_date=None, marketplaceids=()):
data = dict(Action='RequestReport',
ReportType=report_type,
StartDate=start_date,
EndDate=end_date)
data.update(utils.enumerate_param('MarketplaceIdList.Id.', marketplaceids))
return self.make_request(data)
I normally call the function with one of the lines below depending on if I am passing a start_date. Other then having a series of 'if' statements for each request type is there a good way to call this function and only pass a specific variable if it is populated? Over time I will be adding more optional parameters and done want a giant 'if' statement
requested_report=report_api.request_report(report_type=report_name, start_date=starting_date)
requested_report=report_api.request_report(report_type=report_name)
The =... part gives a parameter a default value. Here that's None, and that does mean the parameter is optional when calling the function. If you don't specify it, the default is used. See Default Argument Values in the Python tutorial, as well as the reference documentation for function definitions:
When one or more parameters have the form parameter = expression, the function is said to have “default parameter values.” For a parameter with a default value, the corresponding argument may be omitted from a call, in which case the parameter’s default value is substituted.
When calling such a function, you could pass in the same value as the default, to this specific function that makes no difference; so when there is no starting_date, you can pass in None:
start_date = starting_date or None # when determining the starting date, default to None
requested_report=report_api.request_report(
report_type=report_name,
start_date=starting_date
)
Another option is to set any optional keyword arguments in a dictionary, then pass those in with the ** call syntax to unpack the dictionary as keyword arguments:
kwargs = {}
if ...: # test that decides if start_date is needed
kwargs['start_date'] = starting_date # expression to set the start date
requested_report=report_api.request_report(
report_type=report_name, **kwargs)
It is fine for the kwargs dictionary to be empty.
It is called a default parameter.
Default parameter values are evaluated when the function definition is
executed
Here is the doc on method definition.
Here is additional information

possible variables of a method on python modules

I am new to python, my question is that how we can know the arguments name of a method on a module. for example, in the smpplib module page (https://github.com/podshumok/python-smpplib) i see an example code that has a line as below
client.bind_transceiver(system_id='login', password='secret')
I what to know how i can know that bind_transceiver function has system_id password (and system_type) variable.
help (smpplib.client.Client) just give me below info about bind_transceiver
:
bind_transceiver(self, **args)
Bind as a transmitter and receiver at once
tl;dr You would have to look at the source code or documentation to find out.
Explanation: bind_transmitter uses **args. This allows the person calling the function to pass in any number of keyword arguments. For example:
bind_transmitter() # valid
bind_transmitter(a=1, b='4') # valid
bind_transmitter(myarg=1, m=6, y=7, system_id='me', password='secret') # valid
As such, there is no way to know which keyword arguments bind_transmitter will actually use without examining the source code or documentation.
Sometimes, in Python, functions have **kwargs argument that means "any key - value argument is accepted".
Key-value pairs are passed as in your example:
client.bind_transceiver(system_id='login', password='secret')
The function implementation code access the key - value pairs with the dictionary kwargs. So the internal code would do something like:
def bind_transceiver(self, **kwargs):
# Do something with system id
print(kwargs['system_id'])
# Do something with password
print(kwargs['password])
The output of your call to this function would be
login
password
You can pass any key-value pair to the function but there are only 2 ways to understand which keyes will be actually consumed.
Read the function documentation
Read the code
The keyes that are not used will be stored anyway in the dictionary args within the scope of the function but they won't have any effect.
It is also possible that the function accepts another argument like *args. This, instead of a dictionary, will be read like a tuple by the function in a similar fashion but using positional numbers as keyes.

Python function call, how to pass in multiple function parameters as a single variable string?

I have a Python function that takes one required parameter and four optional ones. If an optional param has no value it needs to be omitted from the call to the function. An example call will be like the following with all params specified.
MyFunction(required='Delta', param1='ABC', param2='XYZ', ID=1234, title='Imp Info')
I would like to gather all of my optional params into a variable and then pass a variable into the function. This will make handling the optional params easier. Something like the following:
myVar = "param2='XYZ', ID=1234, title='Imp Info'"
MyFunction(param1='Delta', myVar)
I've tried the above but it failed with a syntax error. How can I pass function params as a variable? I appreciate any guidance.
Don't pass them in as a string; pass them in as an unpacked dictionary:
myVar = {'param2':'XYZ', 'ID':1234, 'title':'Imp Info'}
MyFunction(param1='Delta', **myVar)
The ** will unpack the dictionary and send each element as a named argument.
You can use MyFunction(parameters, *args, **kwargs), or you can define a method instead that splits the string by space and either parses or uses eval (not recommended) to assign the variable.

Dynamically add keyword arguments

If I have a function:
def add(**kwargs):
for key, value in kwargs.iteritems():
print "%s = %s" % (key, value)
How can I dynamically add keyworded arguments to this function? I am building an HTML Generator in Python, so I need to be able to add keyworded arguments depending on which attributes the user wants to enable.
For instance, if the user wants to use the name attribute in a form, they should be able to declare it in a list of stored keyword arguments (don't know how to do this either). This list of stored keyword arguments should also contain the value of the variable. For instance, if the user wants the attribute name to be "Hello", it should look like and be passed to the function as so:
name = "Hello" (example)
Let me know if you guys need more information. Thanks!
You already accept a dynamic list of keywords. Simply call the function with those keywords:
add(name="Hello")
You can use the **expression call syntax to pass in a dictionary to a function instead, it'll be expanded into keyword arguments (which your **kwargs function parameter will capture again):
attributes = {'name': 'Hello'}
add(**attributes)

Use string variable **kwargs as named argument

I am trying to figure out a way to loop through a json config file and use a key name as the argument name to a method that uses **kwargs. I have created a json config file and used key names as methods. I just append "set_" to the key name to call the correct method. I convert the json to a dictionary to loop through any of the defaults. I want to pass argument names to **kwargs by a string variable. I tried to pass a dictionary but it doesn't seem to like that.
user_defaults = config['default_users'][user]
for option_name, option_value in user_defaults.iteritems():
method = "set_" + option_name
callable_method = getattr(self, method)
callable_method(user = user, option_name = user_defaults[option_name])
Calling the callable_method above passes "option_name" as the actual name of the kwarg. I want to pass it so that when "shell" = option_name that it gets passed as the string name for the argument name. An example is below. That way I can loop through any keys in the config and not worry about what I'm looking for in any method I write to accomplish something.
def set_shell(self, **kwargs):
user = kwargs['user']
shell = kwargs['shell']
## Do things now with stuff
Any help is appreciated I am new to python and still learning how to do things the pythonic way.
If I understand correctly what you're asking, you can just use the ** syntax on the calling side to pass a dict that is converted into kwargs.
callable_method(user=user, **{option_name: user_defaults[option_name]})

Categories