Python Keyword Arguments in Class Methods - python

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

Related

I don’t understand why this won’t print, it says that title is not defined on line 5 even though I defined it in the parenthesis

I defined the problem in the title oops
I have tried so many things I can’t even write them all.
def document(title="cool", genre="fiction"):
print(title+genre)
document(title = "once upon a time ")
document(“awesome”)
document(title+genre)
I expect it to print, once upon a time awesome, cool fiction.
You defined a function which takes two arguments named title and genre. These two arguments are only accessible within your function as local variable. Since these variables aren't declared outside the function, they can not be accessed.
def document(title="cool", genre="fiction"):
print(title+genre)
#declaration of variables
title="foo"
genre="bar"
document(title, genre)
def document(title="cool", genre="fiction"):
This means that the function has two arguments, named title and genre. Each of these has a default value provided, that will be filled in if the caller does not provide them. This is not "defining title" in the way that you seem to be thinking of it. Each function has its own entirely separate set of names for things, as well as the global set of names for things.
print(title+genre)
This means that whatever values were provided, whether they were from the caller or the default values, will be concatenated and printed.
document(title = "once upon a time ")
This says to call the function and use "once upon a time " as the value for title. The value for genre is not provided, so the default value of "fiction" is used. Thus,once upon a time fiction` is printed.
document("awesome")
This says to call the function and use "awesome" as the value for the first parameter. That parameter is the title parameter, so "awesome" is used as the value for title. As before, the value for genre is still "fiction", so awesomefiction is printed.
Note that when the function runs, title is the name that is being used by the function for the string "awesome", even though you didn't say anything about title when you called the function.
document(title+genre)
This says to use whatever are the values of title and genre in the calling context, as the value for the first parameter. But there are no such defined names outside the function. The function's parameters are completely separate and have no meaning whatsoever here. You get a NameError because the names in question are not defined.
You're confusing defining a variable (e.g. title = "once upon a time") with specifying a function argument document(title="whatever"). The latter only specifies the argument passed into document() function, it doesn't define a local variable called title.
And by "inside the parenthesis" you mean "in my function call to document()"
One solution is to do the following:
title = "once upon a time " # <-- actually define a local variable
genre = "Mongolian puppetry"
document(title) # now you can use that variable in your function call
document(“awesome”)
document(title+genre) # ...and reuse that variable again

Is directly returning a modified function parameter a good practice in Python?

I would like to know if it is a good practice to directly return a modified function parameter in Python. Example:
def next_business_day_(day)
while is_weekend(day):
day = day + datetime.timedelta(days=1)
return day
I often see functions written this way (see below), creating a separate variable to return. Is there any upside to do this? Other than the semantic meaning of the newly created variable name (i.e ret)?
def next_business_day(day)
ret = day
while is_weekend(ret):
ret = ret + datetime.timedelta(days=1)
return ret
Both function seem to work, but is there any downside using the first method? (i.e directly return the modified function parameter) which is more concise.
The issue is Python's function parameter evaluation strategy, which is not by value or by reference, but by object.
This by object evaluation strategy implies that you receive inside the function what you send when you make the call. If you pass a variable, you receive a variable but,
if you pass immutable arguments like integers, strings or
tuples to a function, the passing acts like call-by-value. The object
reference is passed to the function parameters. They can't be changed
within the function, because they can't be changed at all, i.e. they
are immutable.
So, your first case would work as long as you (or whoever uses your function) passes a variable as parameter (next_bussiness_day(day_var)), but it would fail if he or she passes an immutable (next_bussiness_day('sunday')).
So, the best practice is the second one.
https://www.python-course.eu/passing_arguments.php

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

Python: call function with default arguments that come before positional arguments

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

passing parameters in python function

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')

Categories