Best Practices: Positional and Keyword Arguments

A function or a method can accept both positional and keyword arguments and that's you who decide whether a function/method will accept positional or keyword argument.

You can choose what is best for your function either positional or keyword parameters according to the requirement.

In this article, you'll learn what are the best practices for positional and keyword arguments.

Positional & Keyword Arguments

Positional arguments are passed positionally in the function/method call while the keyword or named arguments are passed by the parameter's name along with the corresponding values.

# Positional and Keyword Args
def func(p1, p2, p3):
    print(p1, p2, p3)

In this example, the function func() takes three arguments (p1, p2, and p3) and prints them. This function does not explicitly state how the parameters should be passed when you call it.

Consider the following function calls that are all valid.

# Option 1
func("Here", "we", "go")
# Option 2
func("Here", "we", p3="go")
# Option 3
func(p1="Here", p2="we", p3="go")
# Option 4
func("Here", p2="we", p3="go")

--------------------
Here we go
Here we go
Here we go
Here we go

Well, this looks fine that you have the flexibility to pass arguments as you wish until you are following the correct way.

Stick to the Rule

You need to stick to the rule when passing a combination of positional and keyword arguments.

The following function call will result in an error as it violates the syntax set by Python.

func("Here", p2="we", "go")

The p1 and p3 are passed positionally while the p2 is passed as a keyword argument.

...
    func("Here", p2="we", "go")
                              ^
SyntaxError: positional argument follows keyword argument

You can see that this program raised a SyntaxError stating that the positional argument cannot be passed after the keyword argument.

When you pass the keyword argument to a function, all subsequent arguments must also be passed as keywords. Positional arguments should always come before keyword arguments.

Restrict Arguments to be Positional-only and Keyword-only

One of the best practices is to bound the arguments to be positional-only and keyword-only.

You can create a function that accepts simply positional arguments, keyword arguments, or a combination of the two.

Here's how you can achieve it.

# Takes Positional-only Args
def func1(p1, p2, p3, /):
    print(p1, p2, p3)

# Takes Keyword-only Args
def func2(*, kw1, kw2, kw3):
    print(kw1, kw2, kw3)

# Takes Mix Args
def func3(pos, /, pos_kw, *, kw):
    print(pos, p_kw, kw)

In this example, the function func1() allows only positional arguments due to the slash (/) at the end of the function definition, likewise, the function func2() allows only keyword arguments because of the asterisk (*) at the beginning.

But, the function func3() accepts mixed arguments because pos is positional-only, pos_kw can be positional or keyword, and kw is keyword-only.

Read - Why Slash and Asterisk Used in Function Definition?

# Passed positional-only args
func1("positional", "only", "arguments")
# Passed keyword-only args
func2(kw1="keyword", kw2="only", kw3="arguments")
# Passed mixed args
func3("mixed", "arguments", kw="passed")

--------------------
positional only arguments
keyword only arguments
mixed arguments passed

This approach can be useful when developing an API and you don't want users to pass values through the parameter name. In that situation, you can configure the API to only accept positional values, and you can modify the parameter name in the future without breaking anything.

Also, if you're writing a function for e-commerce, you can utilise keyword-only parameters to avoid confusion between price, item, and so on.

Optional Arguments/Arguments with Default Value

You can set a default value for an argument if you need to by assigning a value to the parameter in the function definition.

# Function with an optional param
def optional_param(name, age, height=170):
    print(f"Name  : {name}")
    print(f"Age   : {age}")
    print(f"Height: {height}")

The function optional_param() has a height parameter set to a default value of 170. If you don't pass it in a function call, Python will assign that default value. This means that it became an optional argument.

optional_param("John", 32)
--------------------
Name  : John
Age   : 32
Height: 170

You can override the default value by specifying a different value. This can be helpful when you want to set a minimum or a maximum limit.

Variadic Arguments

When you're unsure or don't want to specify a big list of parameters in a function definition, make it accept a variadic (any number of arguments) argument instead.

# Takes any no. of args
def send_invitation(*args):
    print("Invitation sent to:")
    for everyone in args:
        print(everyone)

You can pass any number of positional arguments to the function send_invitation() due to *args. This *args expression indicates that the function can accept any number of arguments and the values are stored in a tuple.

send_invitation(
    "John",
    "Max",
    "Cindy"
)
--------------------
Invitation sent to:
John
Max
Cindy

Likewise, you can make a function accept variadic keyword arguments using **kwargs.

# Takes any no. of keyword args
def party_items(**kwargs):
    print("Party items:")
    for key, value in kwargs.items():
        print(f"{key}: {value}")

party_items(
    Poppers=3,
    Ballons=120,
    Sparkles=10
)

The **kwargs stores keyword arguments as the key/value pair in a dictionary, so you can perform any related operations on the keys and values.

Read - Understanding \args and \*kwargs in Python**.

Argument Ordering

Arguments must be passed in the same order as the parameters appear in the function definition.

def details(name, age, occupation):
    print(f"Name      : {name}")
    print(f"Age       : {age}")
    print(f"Occupation: {occupation}")

details(32, "John", "Writer")

When you run this code, you'll get the name as 32 and the age as John due to a messed up argument order when the function is called.

Name      : 32
Age       : John
Occupation: Writer

But if you pass the values using the parameter name in any order, you'll get the desired result.

details(age=32, name="John", occupation="Writer")
--------------------
Name      : John
Age       : 32
Occupation: Writer

This is not the ideal approach because each function will differ; for example, you may create functions that accept only positional or keyword arguments.

So, the bottom line is to always pass the arguments in order as the parameters appear in the function definition.

Argument Type Hinting

It's not a terrible idea to specify what argument type should be given when invoking the function. This will indicate that the specified type of argument should be passed.

# Type hinting
def func(arg1: int, arg2: float):
    print(f"{arg1} type: {type(arg1)}")
    print(f"{arg2} type: {type(arg2)}")

When you call the function func(), arg1 should be passed as an integer and arg2 should be passed as a decimal number. This is called type hinting.

func(2, 3.9)
--------------------
2 type: <class 'int'>
3.9 type: <class 'float'>

It's not like you must pass those specified types of arguments, you can pass any type as you wish, and Python won't throw an error because the interpreter completely ignores the type hints.

func("2", 3.9)
--------------------
2 type: <class 'str'>
3.9 type: <class 'float'>

Python is a dynamically typed language, so type hints won't be very useful but in some cases, they can be helpful to avoid bugs.

Naming the Arguments Properly

You must name your parameters in a way that defines their purpose. Let's say you are creating a program for a vehicle company, so you must name your parameters according to that for better readability.

Conclusion

Python provides a lot of freedom to developers. Each programming language is distinct and different, and following best practices elevates them even further.

A developer should understand how to get the most out of the programming language, including how to leverage their experience and best practices.

In this article, you've learned some of the best practices for positional and keyword arguments that are as follows:

  • Sticking to the proper syntax for passing the positional and keyword arguments

  • Making the function accept only positional or keyword arguments or mixed arguments

  • Setting a default value for the argument

  • If you are unsure how many arguments should a function accept, use variadic arguments (*args and **kwargs) in that case.

  • Arguments should be correctly placed to avoid unpredictable behaviour.

  • Can use type hints to avoid bugs

  • Name the parameters in a way that defines their purpose


🏆Other articles you might be interested in if you liked this one

Understanding args and kwargs in Python: Best Practices and Guide

Why Slash and Asterisk Used in Function Definition?

Create a WebSocket Server and Client in Python.

Decorators in Python and How to Create a Custom Decorator?

Understanding the Different Uses of the Asterisk(*) in Python?

The map() Function in Python for Mapping a Function to Each Item in the Iterable?


That's all for now

Keep Coding✌✌

Did you find this article valuable?

Support Team - GeekPython by becoming a sponsor. Any amount is appreciated!