Positional argument vs keyword argument - python

Based on this
A positional argument is a name that is not followed by an equal sign
(=) and default value.
A keyword argument is followed by an equal sign and an expression that
gives its default value.
def rectangleArea(width, height):
return width * height
print rectangleArea(width=1, height=2)
Question. I assume that both width and height are positional arguments. Then why can we also call it with the keyword argument syntax?

That text you quote seems to be confused about two totally different things:
Positional and keyword arguments are a feature of calls to a function (see Python reference section 5.3.4 Calls).
Default values are a feature of function definitions, as per section 7.6 Function definitions
I suspect the people who put together that course-ware weren't totally familiar with Python :-) Hence that link you provide is not a very good quality one.
In your call to your function, you're using the "keyword argument" feature (where the argument is named rather than relying on its position). Without that, values are bound to names based on order alone. So, in this example, the two calls below are equivalent:
def process_a_and_b(a, b):
blah_blah_blah()
process_a_and_b(1, 2)
process_a_and_b(b=2, a=1)
By further way of example, refer to the following definition and calls:
def fn(a, b, c=1): # a/b required, c optional.
return a * b + c
print(fn(1, 2)) # returns 3, positional and default.
print(fn(1, 2, 3)) # returns 5, positional.
print(fn(c=5, b=2, a=2)) # returns 9, named.
print(fn(b=2, a=2)) # returns 5, named and default.
print(fn(5, c=2, b=1)) # returns 7, positional and named.
print(fn(8, b=0)) # returns 1, positional, named and default.

Positional parameters, keyword parameters, required parameters and optional parameters are often confused. Positional parameters are not the same as required parameters, and keywords parameters are not the same as optional parameters.
Positional(-only) parameters are bound to positional arguments provided in a call, that is by position. They were introduced in Python 3.8.
Keyword(-only) parameters are bound to keyword arguments provided in a call, that is by name.
Positional-or-keyword parameters are bound to positional arguments or keyword arguments provided in a call, that is either by position or by name.
Required parameters are bound to arguments provided in a call.
Optional parameters are bound to default arguments provided in a definition.
This is the Python syntax for declaring parameters:
def f(positional_parameter, /, positional_or_keyword_parameter, *, keyword_parameter):
pass
Positional parameter that is required (since Python 3.8):
def f(a, /):
pass
f() # error, argument is required
f(1) # allowed, positional argument
f(a=1) # error, keyword argument
Positional parameter that is optional (since Python 3.8):
def f(a=2, /):
pass
f() # allowed, argument is optional
f(1) # allowed, positional argument
f(a=1) # error, keyword argument
Keyword parameter that is required:
def f(*, a):
pass
f() # error, argument is required
f(1) # error, positional argument
f(a=1) # allowed, keyword argument
Keyword parameter that is optional:
def f(*, a=1):
pass
f() # allowed, argument is optional
f(1) # error, positional argument
f(a=1) # allowed, keyword argument
Positional-or-keyword parameter that is required:
def f(a):
pass
f() # error, argument is required
f(1) # allowed, positional argument
f(a=1) # allowed, keyword argument
# In fact that function is the same as this one.
def f(/, a, *):
pass
Positional-or-keyword parameter that is optional:
def f(a=1):
pass
f() # allowed, argument is optional
f(1) # allowed, positional argument
f(a=1) # allowed, keyword argument
# In fact that function is the same as this one.
def f(/, a=1, *):
pass
Conclusion. — A parameter can be required or optional but not both at the same time. It can also be positional, keyword, or both at the same time.

A keyword argument is just a positional argument with a default value. You must specify all arguments that don't have a default value. In other words, keyword arguments are only "optional" because they will be set to their default value if not specifically supplied.

First, a parameter is a named entity in the function/method definition that specifies an argument. An argument is a value passed to a function.
For example,
def rectangle_area(height, width):
pass
rectangle_area(argument_1, argument_2)
height, width are the function parameters, and argument_1, argument_2 are the arguments passed to the function. When you say positional argument, you are talking about arguments, this has nothing to do with the function definition. width and height are (by default in Python) positional parameters or keyword parameters (so called positional-or-keyword parameters). Therefore, you could pass arguments either positionally or by keywords.
How you are calling/passing the value to the function determines if they are positional arguments or keyword arguments.
For the function rectangle_area we could call it equally like so:
rectangle_area(1, 2) # positional arguments
rectangle_area(width=2, height=1) # keyword arguments
In the first calling, we pass values positionally: 1 is passed to the height and 2 to the width. That is, Python infers that when you say 1, 2 we mean height is 1 and width is 2 based on the position they are passed (i.e., in the function definition the first parameter is the height and the second is the width).
In the second calling, we pass values by keywords. We are hinting to Python which parameter we are passing the argument to. In the second example, we flip the order of the arguments, yet we tell Python that height is still 1 and width is still 2. Both callings have exactly the same result.
positional-only and keyword-only
The thing not many people know is that you can specify a positional-only parameter by using the / in the parameter list (example from here).
def func(positional_only1, positional_only2, /, positional_or_keyword): ...
Similarly, you can also have keyword-only parameters by using the * character.
def func(positional_or_keyword, *, keyword_only1, keyword_only2): ...
Finally, we also have var-positional and var-keyword (a.k.a *args and **kwargs respectively). Meaning, you can have arbitrary sequence of positional arguments or keyword arguments passed to the function.

Positional arguments can be called either using values in order or by naming each. For example, all three of the following would work the same way:
def rectangleArea(width, height):
return width * height
print(rectangleArea(1, 2))
print(rectangleArea(width=1, height=2))
print(rectangleArea(height=2, width=1))

positional arguments: arguments passed to a function in correct positional order. below program understand the positional arguments of a function
#positional arguments example
def combine(str1, str2):
#To join str1 and str2 with str3
str3 = str1 + str2
print(str3)
#call combine() and pass 2 strings
combine("Well", "come") #positional arguments
suppose, we passed 'come' first, 'well' second, then the result will be comewell. also, call the function 3 strings become error.

Understand the keyword arguments of a function.
Keyword arguments are arguments that identify the parameters by their names.
#keyword arguments example:
def employee(name, Id):
print("Employee Name: ", name)
print("Employee Id : ", Id)
#call employee() and pass 2 arguments
employee(name = "inban", Id = "pay001")
employee(Id = "pay002", name = "karthik") #we can change the order args.

I assume that both width and height are positional arguments. Then why can we also call it with the keyword argument syntax?
To prevent that you can use positional-only arguments:
def rectangleArea(width, height, /):
return width * height
print rectangleArea(width=1, height=2)
The error message would be as follows:
TypeError: rectangleArea() got some positional-only arguments passed as keyword arguments: 'width, height'

Here is some extra information to complete #Nazime Lakehal’s excellent answer.
A positional parameter that is optional cannot be followed by a positional parameter or positional-or-keyword parameter that is required:
# SyntaxError.
def f(a=1, b, /):
pass
# SyntaxError.
def f(a=1, /, b):
pass
A positional-or-keyword parameter that is optional cannot be followed by a positional-or-keyword parameter that is required:
# SyntaxError.
def f(a=1, b):
pass
For binding a positional parameter that is optional, all previous positional parameters that are optional have to be bound, making them all effectively required. That may be the origin of the confusion of positional parameters with required parameters:
def f(a=1, b=2, /):
pass
f(1, 0)
For binding a keyword parameter or positional-or-keyword parameter that is optional, all other keyword parameters and positional-or-keyword parameters that are optional do not have to be bound. That may be the origin of the confusion of keyword parameters with optional parameters:
def f(c=3, *, a=1, b=2):
pass
f(b=0)
def f(a=1, b=2, *, c=3):
pass
f(b=0)

Related

Default values for positional function arguments in Python?

I was going trough some code, and I came across the following function:
def foo(self, arg1=1, *, arg2=2):
pass
I was surprised to see keyword arguments on the left side of the *, the positional arguments. I notice then that I can call foo in both of the following ways:
>>> foo(1)
>>> foo(arg1=1)
I think I would be expecting the second call to fail as I am calling foo using a named argument by providing the keyword arg1.
With that said, am I using positional arguments in both scenarios, or is the second call to foo a named argument?
The best sentence that I found that best describes this is:
"The trick here is to realize that a “keyword argument” is a concept of the call site, not the declaration. But a “keyword only argument” is a concept of the declaration, not the call site."
Below is a concise explanation copied from here in case the link dies at some point.
def bar(a, # <- this parameter is a normal python parameter
b=1, # <- this is a parameter with a default value
*, # <- all parameters after this are keyword only
c=2, # <- keyword only argument with default value
d): # <- keyword only argument without default value
pass
The arg1 argument is allowed to be called as either a positional argument, or a keyword argument.
As of Python 3.8, it is possible to specify some arguments as positional only. See PEP 570. Prior to 3.8, this isn't possible unless you write a python C extension.
The 3.8 syntax looks like this (directly from the PEP):
def name(positional_only_parameters, /, positional_or_keyword_parameters,
*, keyword_only_parameters): ...
...prior to 3.8, the only legal syntax is this:
def name(positional_or_keyword_parameters, *, keyword_only_parameters): ...
Despite the similarity in syntax, there is no relationship between keyword arguments and parameters with default values.
key=value is used both to assign a default value to a parameter when the function is defined, and to pass an argument for a parameter when the function is called.
A parameter without a default value can be assigned using a keyword argument:
def foo(a):
return a + 3
assert foo(a=5) == 8
A parameter with a default value can be assigned without a keyword argument:
def foo(a=5):
return a + 3
assert foo() == 8
assert foo(1) == 4
Is a complex answer by using the * like the argument ( the Python version, define and use it ).
In your case:
>>> foo(1,2,)
>>> foo(1,2)
Note that:
Try to use this and see the difference ( without self ):
>>> def foo( arg1=1, *, arg2=2):
... pass
...
>>> foo(arg1=1,arg2=2)
>>> def foo( arg1=1, *, arg2=2):
... pass
...
>>> foo(arg1=1,arg2=2)
>>> foo(arg1=1)
>>> foo(arg1=1,)
>>> foo(arg2=2)
>>> foo(arg2=2,1)
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
>>> foo(2,1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes from 0 to 1 positional arguments but 2 were given
>>> foo(arg1=1,2)
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
One star * defines positional arguments (you can receive any number of arguments and treat the passed arguments as a tuple);
Two stars ** define keywords arguments.
A good example comes from this tutorial (the keyword-only arguments without positional arguments part):
def with_previous(iterable, *, fillvalue=None):
"""Yield each iterable item along with the item before it."""
previous = fillvalue
for item in iterable:
yield previous, item
previous = item
>>> list(with_previous([2, 1, 3], fillvalue=0))
[(0, 2), (2, 1), (1, 3)]
That its value could be sent as positional arguments.
See this tutorial for more info about arguments.
Python 3.x introduces more intuitive keyword-only arguments with PEP-3102 (you can specify * in the argument list).
One good alternative answer is this:

The *arguments position in definition of a function

I defined a function like this:
def func(must, op1=1, op2=2, op3=3, *arguments, **keywords):
print(must, op1, op2, op3)
for arg in arguments:
print(arg)
for kw in keywords.keys():
print(kw, ":", keywords[kw])
I called it:
func(1, op1=1, op2=2, op3=3, 1, 3)
Of course, I got an error:
Error information
In my mind, *arguments are positional parameter. And the op1, op2, op2 are keyword parameters. So *arguments should be before op1, op2, op3. Then I changed the definition:
def func(must, *arguments, op1=1, op2=2, op3=3, **keywords):
print(must, op1, op2, op3)
for arg in arguments:
print (arg)
for kw in keywords.keys():
print (kw, ":", keywords[kw])
Why doesn't the Python interpreter think the first definition is a mistake?
Hi All,
I updated this topic.
After discuss with my colleague, I think that:
definition of a function, the parameters are default or non-default parameters
call a function, the parameters are positional or keyword parameters
So, whether the parameter is a positional parameter depends on you call the function, not define the function.
While slightly counterintuitive, the first definition is completely unambiguous:
func(must, op1=1, op2=2, op3=3, *args, **kwargs)
This means that op1, op2, and op3 are optional positional arguments. You can't specify any of *args without explicitly setting all three first. You got the error because you attempted to place positional arguments after keywords. It's irrelevant that the keywords name positional arguments. You can make the same call like this:
func(1, 1, 2, 3, 1, 3)
That will not raise an error. Neither will
func(1, 2)
In that case, only op1 will have a non-default value, *args will be empty, and you can set whatever keywords you want, including op2 and op3.
Aside from *args, all positional arguments are named and can be passed in by keyword as well. In practice, though, all arguments that come after the first one passed in as a keyword must be passed in as a keyword. It therefore follows that you can't pass in *args if you pass in any named positional argument as a keyword.
In your second example, you've made the op arguments keyword-only by placing them after the splat (*). Any positional arguments after the first are therefore absorbed into *args.
Keep in mind that keyword-only arguments don't need defaults. A function like def func(*, a): pass can only be invoked as func(a=3) and never as func(3).
On a side note, the splat argument is conventionally named *args and the splatty splat one **kwargs. I have stuck with that convention throughout my answer.
At the first example, you can call your function like this (it's still working):
func(9, 9, 9, 9)
Python determine which parameter is keyword when you call a function.
Here's more example:
def func(a,b,c=1,d): # -> a, b, c, d are parameters and c has default value = 1
pass
func(1, 2, 3, 4) # -> call with 4 postional parameters
func(1, 3, d=3) # -> call with 2 positional parameters and 1 keyword parameters

"None" in Python

So, I have this pretty simple function (I'm a novice still).
And it goes like:
def add_num(x,y,z=None):
if z == None:
return x+y
else:
return x+y+z
print(add_num(1,2))
print(add_num(1,2,3))
So my question is, when I notice that if there is no third variable, then it is accepted. So does "None" mean basically mean that it is ok to have no value attached to a variable if "variable=None." Just confirming! Thanks!
So does "None" mean basically mean that it is ok to have no value attached to a variable if "variable=None." Just confirming! Thanks!
No. When you define a function like this:
def add_num(x,y,z=None):
x and y are "positional" arguments, and they are required, while z is a keyword argument. Keyword arguments have default values that will be used if you don't provide one when you call the function. Instead of None, you could just as easily have written:
def add_num(x,y,z=0):
Or:
def add_num(x,y,z=5):
Etc. In either case, you are setting a default value for z if it is not provided in the function call.
Note that if you have multiple keyword arguments, like this:
def do_something(x, y, size='medium', name=None):
That you can provide them with values as positional arguments, in which case the arguments need to be in the matching order:
do_something(1,2, 'large', 'alice')
But you can also specify keyword arguments in an arbitrary order by providing their name in the function call, like this:
do_something(1, 2, name='alice', size='large)
And you don't need to provide values if you are happy with the default:
do_something(1, 2, name='alice')
Try this:
def add_num(x,y,z='spatula'):
if z == 'spatula':
return x+y
else:
return x+y+z
print(add_num(1,2))
print(add_num(1,2,3))
None is common to use here, but it's not intrinsic to default arguments.
I ought to take a look at the python tutorial. Especially Default Argument Values
This chapter explains how to define a function with default arguments.
The next is about Keyword arguments: Functions can also be called using keyword arguments of the form kwarg=value.
There are two kinds of argument:
keyword argument: an argument preceded by an identifier (e.g. name=) in a function call or passed as a value in a dictionary preceded by **. For example, 3 and 5 are both keyword arguments in the following calls to complex():
complex(real=3, imag=5)
complex(**{'real': 3, 'imag': 5})
positional argument: an argument that is not a keyword argument. Positional arguments can appear at the beginning of an argument list and/or be passed as elements of an iterable preceded by *. For example, 3 and 5 are both positional arguments in the following calls:
complex(3, 5)
complex(*(3, 5))
Arguments are assigned to the named local variables in a function body.

I am learning python3, but I can not understand how to define method arguments

I known the python defined two type method arguments:
position arguments
keyword arguments
and position arguments can divided into three types:
plain position arguments
default arguments
variable arguments
Similarly, the keyword arguments divided below three types:
optional (keyword) arguments
named keyword arguments
plain keyword arguments
So, I defined a method:
def method(a, b=1, *c, d = 'default', e, **f)
print(a, b, c, d, e, f)
I have some confusion:
In the calling method, whether can use the keyword arguments for position arguments, such as:
method(b=2, a=1, c=[1,2,3], e=4)
I think the default parameters can replace named keyword, but why introduce optional (keyword) arguments?
My understanding is there a problem?

python: constructor argument notation

I'm a few months into learning python.
After going through pyramid tutorials I'm having trouble understanding a line in the init.py
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
from .models import (
DBSession,
Base,
)
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
DBSession.configure(bind=engine)
Base.metadata.bind = engine
config = Configurator(settings=settings)
config.include('pyramid_chameleon')
config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('home', '/')
config.scan()
return config.make_wsgi_app()
I'm lost about settings=settings in the configurator argument.
What is this telling python?
Python functions support keyword arguments:
def add(a, b):
return a + b
add(a=1, b=2)
This happens here.
Configurator(settings=settings)
The first settings is the name of the parameter in the __init__ of Configurator. The second is a name for an object in the current name space.
Python supports calling any callable object (i.e. functions, constructors, or even objects understanding __call__ method) specifying positional arguments, named arguments, or even both types of arguments.
When you pass named arguments, they must be after the positional arguments (if any is passed).
So you can call any function, like:
def f(a, b):
return a + b
In the following ways:
f(1, 2)
f(1, b=2)
f(a=1, b=2)
f(b=1, a=2) # Order doesn't matter among named arguments
While the following forms will trigger an error:
f(a=1, 2) # Named arguments must appear AFTER positional arguments
f(1, a=2) # You are passing the same argument twice: one by position, one by name
So, when you pass a named parameter, be sure you don't pass the same parameter twice (i.e. also by position), and also check that the argument name exists (also: if it is documented that the argument could/should be passed by name, respect their names on inheritance/override).
Additionally Python supports passing *arguments and **keyword_arguments. These are additional arguments you can process in a variadic way, as many languages support them.
*args (the name doesn't matter - it must have an asterisk to be a positional variadic; it's a tuple) holds remaining unmatched positional arguments (instead of getting a TypeError for positional argument being unexpected, such argument gets into *args as an element).
**kwargs (the name doesn't matter - it must have two asterisks to be a named/keyword variadic; it's a dictionary) holds the remaining unmatched named arguments (instead of getting a TypeError for named argument being unexpected, such argument gets into **kwargs as an element).
So, perhaps you see a function like this:
def f(*args, **kwargs):
...
You can call it with any parameters you want:
f(1, 2, 3, a=4, b=5, c=6)
Just keep the order: named arguments come after positional arguments.
You can declare a function like this:
f(m1, m2, ..., o1=1, o2=2, ..., *args, **kwargs):
pass
Understanding the following:
m1, m2, ... are mandatory: when you call, you must fill them either positionally or respecting their name.
o1, o2, ... are optional: when you call, you can omit such parameters (omitting them implies not passing them by position nor by name), and they will hold the value after the equal sign (such value is evaluated when the function is declared - avoid using mutable objects as their values).
args and kwargs are what I explained you before: Any unmatched argument by position and by name go into these parameters. With these features, you will have a clear distinction between what is a parameter and what is an argument.
All these parameters are optional. You can choose not to use mandatory and only optionals. You can choose not to use *args but yes **kwargs, and so. But respect the order in the declaration: mandatory, optional, *args, **kwargs.
When you call the method and pass the arguments the semantic is very different so be wary:
f(1) # passes a positional argument. Has nothing to do with the parameter being mandatory.
f(a=1) # passes a named argument. Has nothing to do with the parameter being optional.
f(**i) # UNPACKS the positional arguments. Has nothing to do with the function having a *args parameter, but *args will hold any unpacked -but unmatched- positional argument from i (which is any type of sequence or generator)
f(**d) # UNPACKS its values as named arguments. Has nothing to do with the function having a **kwargs parameter, but **kwargs will hold any unpacked -but unmatched- argument from d (which is a dict having string keys).
When you make the call, you can pass them as you like, which has nothing to do with the actual method signature (i.e. expected parameters), but respect the order as with parameters: positional, named, *positionalUnpack, **keywordUnpack, or you will get a nice TypeError.
Examples:
def f(a, b=1, *args, **kwargs):
pass
Valid calls:
f(1) # a = 1, b = 2, args = (), kwargs = {}
f(*[1]) #a = 1, b = 2, args = (), kwargs = {}
f(*[3, 4]) #a = 3, b = 4, args = (), kwargs = {}
f(**{'a':1, 'b':3}) #a = 1, b=3, args = (), kwargs = {}
f(1, *[2, 3, 4], **{'c': 5}) #a = 1, b=2, args=(3, 4), kwargs = {'c': 5}
Again beware:
Do not pass the same parameter twice (a clash would occur between **unpacked arguments with other named arguments, or positional arguments, or *unpacked arguments).
If you want to pass *args or **kwargs to a super call, ensure using the unpack syntax:
def my_method(self, a, b, *args, **kwargs):
super(MyClass, self).my_method(a+1, b+1, *args, **kwargs)
It's saying that it is passing the local name settings as the argument named settings in the Configurator.
For a function or constructor call of the form x=y, the x is the argument name used locally on the function/constructor side, while y is the name on the caller side. They just happen to be the same name in this case.
That means that you are passing the argument settings to Configurator which contains a variable called settings
here an example, you have a function:
def function_test(a=None, b=None, c=None):
pass
You could call it like that:
c = "something"
function_test(c=c)
which mean you passed the variable c that you created as an argument for the parameter c in the function function_test

Categories