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
Related
Is there a way in Python to pass optional parameters to a function while calling it and in the function definition have some code based on "only if the optional parameter is passed"
The Python 2 documentation, 7.6. Function definitions gives you a couple of ways to detect whether a caller supplied an optional parameter.
First, you can use special formal parameter syntax *. If the function definition has a formal parameter preceded by a single *, then Python populates that parameter with any positional parameters that aren't matched by preceding formal parameters (as a tuple). If the function definition has a formal parameter preceded by **, then Python populates that parameter with any keyword parameters that aren't matched by preceding formal parameters (as a dict). The function's implementation can check the contents of these parameters for any "optional parameters" of the sort you want.
For instance, here's a function opt_fun which takes two positional parameters x1 and x2, and looks for another keyword parameter named "optional".
>>> def opt_fun(x1, x2, *positional_parameters, **keyword_parameters):
... if ('optional' in keyword_parameters):
... print 'optional parameter found, it is ', keyword_parameters['optional']
... else:
... print 'no optional parameter, sorry'
...
>>> opt_fun(1, 2)
no optional parameter, sorry
>>> opt_fun(1,2, optional="yes")
optional parameter found, it is yes
>>> opt_fun(1,2, another="yes")
no optional parameter, sorry
Second, you can supply a default parameter value of some value like None which a caller would never use. If the parameter has this default value, you know the caller did not specify the parameter. If the parameter has a non-default value, you know it came from the caller.
def my_func(mandatory_arg, optional_arg=100):
print(mandatory_arg, optional_arg)
http://docs.python.org/2/tutorial/controlflow.html#default-argument-values
I find this more readable than using **kwargs.
To determine if an argument was passed at all, I use a custom utility object as the default value:
MISSING = object()
def func(arg=MISSING):
if arg is MISSING:
...
def op(a=4,b=6):
add = a+b
print add
i)op() [o/p: will be (4+6)=10]
ii)op(99) [o/p: will be (99+6)=105]
iii)op(1,1) [o/p: will be (1+1)=2]
Note:
If none or one parameter is passed the default passed parameter will be considered for the function.
If you want give some default value to a parameter assign value in (). like (x =10). But important is first should compulsory argument then default value.
eg.
(y, x =10)
but
(x=10, y) is wrong
You can specify a default value for the optional argument with something that would never passed to the function and check it with the is operator:
class _NO_DEFAULT:
def __repr__(self):return "<no default>"
_NO_DEFAULT = _NO_DEFAULT()
def func(optional= _NO_DEFAULT):
if optional is _NO_DEFAULT:
print("the optional argument was not passed")
else:
print("the optional argument was:",optional)
then as long as you do not do func(_NO_DEFAULT) you can be accurately detect whether the argument was passed or not, and unlike the accepted answer you don't have to worry about side effects of ** notation:
# these two work the same as using **
func()
func(optional=1)
# the optional argument can be positional or keyword unlike using **
func(1)
#this correctly raises an error where as it would need to be explicitly checked when using **
func(invalid_arg=7)
For example, I'd like to do something like: greet(,'hola'), where greet is:
def greet(person='stranger', greeting='hello')
This would help greatly for testing while writing code
Upon calling a function you can use the variable names to make it even more clear what variable will assume which value. At the same time, if defaults are provided in the function definition, skipping variables when calling the function does not raise any errors. So, in short you can just do this:
def greet(person='stranger', greeting='hello')
print('{} {}'.format(greeting, person))
return
greet(greeting='hola') # same as greet(person='stranger', greeting='hola')
# returns 'hola stranger'
Note that, as I said above this would not work if for example your function definition was like this:
def greet(person, greeting)
print('{} {}'.format(greeting, person))
return
Since in this case, Python would complain saying that it does not know what to do with person; no default is supplied..
And by the way, the problem you are describing is most likely the very reason defaults are used in the first place
Without knowing the other parameters, and only knowing that the parameter you want to change is in second position you could use the inspect module to get function signature & associated default values.
Then make a copy of the default values list and change the one at the index you want:
import inspect
def greet(person='stranger', greeting='hello'):
print(person,greeting)
argspec = inspect.getargspec(greet)
defaults = list(argspec.defaults)
defaults[1] = "hola" # change second default parameter
greet(**dict(zip(argspec.args,defaults)))
Assuming that all parameters have default values (else it shifts the lists an that fails) that prints:
stranger hola
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.
I have written one method in python as follows :
def report(self,year,month):
print year,month
emptylist=[]
parameter month is optional. Sometimes it's NOT passed from the caller function but sometimes it is passed.How is this different from the following code ?
def func(self,*args,**kwargs):print args,kwargs I know this has simple answer but I'm new to python and programming stuff. Please help me out.
If month has a default value, you can try
def report(self, year, month='default_value'):
print year, month
emptylist = []
The value of month gets overwritten if passed
In addition to Ashoka's answer, it's normally a good idea to use None as the default value in the method's signature and assign the true default value with in function body. This makes it easier to wrap the function, pass arguments, and it also avoids problems with mutable default values.
def func(kwarg=None):
if kwarg is None:
kwarg = 'default'
print(kwarg)
func()
func(kwarg='Hello')
I'm attempting to write a class method that takes 3 keyword arguments. I've used keyword arguments before but can't seem to get it to work inside of my class. The following code:
def gamesplayed(self, team = None, startyear = self._firstseason,
endyear = self._lastseason):
totalGames = 0
for i in self._seasons:
if((i.getTeam() == team or team == "null") and
i.getYear() >= startyear and i.getYear() <= endyear):
totalGames += i .getGames()
return totalGames
produces the error:
NameError: name 'self' is not defined
If I take out the keyword arguments and make them simple positional ones, it works fine. Therefore I am not sure where my problems lies. Thanks in advance for any help.
def gamesplayed(self, team = None, startyear = self._firstseason, endyear = self._lastseason):
In the function declaration you are trying to reference instance variables using self. This however does not work as self is just a variable name for the first argument of the function which gets a reference to the current instance passed in. As such, self is especially not a keyword that always points to the current instance (unlike this in other languages). This also means that the variable is not yet defined during the declaration of the function.
What you should do is to simply preset those parameters with None, and preset them to those values in that case inside the function body. This also allows users to actually parse a value to the method that results in the default values without having to actually access the values from somewhere inside your class.
Default values for keyword arguments are bound at module construction time, not at class instance construction time. This is why self is not defined in this context.
The same fact about default values can create all sorts of problems any time you want a keyword argument where the default value updates every time the function is called. When you run the program, you'll find that the default value you expect to be updating is always set to the value constructed when the module was first initialized.
I would advise using None as a default keyword parameter in both instances, as poke and others have suggested. Your code could look something like:
def gamesplayed(self, team=None, startyear=None, endyear=None):
if not startyear:
startyear = self._firstseason
if not endyear:
endyear = self._lastseason