What's that *args stuff in Python?

What's that *args stuff in Python?

We've all called functions or methods of a class and then we see our editor show stuffs like so:

Image description

The focus is on *values part of the picture.

Most times, we just use the thing and go our way.

In this post, we'll see the purpose of that asterisk stuff (usually called *args) and how to use it to eliminate boredom and reduce tension in our Python functions and methods.

The problem

Y'all remember Isaac? Well, he's got a problem here.

Isaac has been employed by Genghis Khan, one of the greatest men the world will ever see, to automate the process of ending the lives of his enemies.

This is Isaac's second serious job and he is ready to impress the Emperor of the Mongol Empire, so he creates an dispatch_foe function that accepts a list of names of people and then reduce pollution by doing what is necessary.

He churns a function like so:

from GenghisKhan.actions import kill

def dispatch_foe(name: str) -> bool:
    success: bool = kill(name) # ends the life

    return success

The issue

Calling this function on lots of people involves doing something like so:

for name in list_of_names:
    dispatch_foe(name)

This could be quite laborious for the soldiers involved and only does the dirty work for them. It does not really automate lots.

A small solution

Well, Isaac then decides to make his function accept a list of the names and then do the rest:

from typing import List
from GenghisKhan.actions import kill

def dispatch_foe(names: List) -> bool:
    success: bool = True
    for name in names:
        success = success and kill(name) # tells us if and only if everyone died

    return success

and we can call dispatch_foe like so:

# people who we both share mutual hate
enemies = ["Erons", "Victor Aiyeola", "Davidemi"]

# test to confirm that they were successfully dispatched
assert True is dispatch_foe(enemies)

An actual solution (The why)

While Isaac's solution works, it is stupid. Why? Simply because if we accept it, I'll never be able to teach you what *args does. That means you'll wallow in complete ignorance till the end of your life span.

This has a dangerous effect. In the event the life of someone can only be saved by *args, our refusal to reject Isaac's answer will spell the end of that person who may be a key soul to solving world hunger and therefore lead to millions and billions of deaths. This is why we always have to reject Isaac's first solution to solving any problem.

Actually... lol

Most times, you'd want your function to accept a variable number of arguments without specifying a default. *args is a beautiful and pythonic way to do that.

So we'd use it instead of lists or tuples or dictionaries (ah, there's a trick to this one, I'll write an article on it someday) or sets or arrays or vectors or linked lists or doubly linked lists or triply linked lists or quadruply linked lists or ...

An actual solution (The real stuff, without ment attached)

So, we'll rework Isaac's solution so soldiers can pass as many enemies as possible without having to pack them into a list:

from typing import Sequence
from GenghisKhan.actions import kill

def dispatch_foe(*names: Sequence[str]) -> bool:
    success: bool = True
    for name in names:
        success = success and kill(name) # tells us if and only if everyone died

    return success

and we can call our function in different ways like so:

# 'do' Erons alone
assert True is dispatch_foe("Erons")

# 'do' Erons and someone else
assert True is dispatch_foe("Erons", "Someone else")

# 'do' people who hate me
assert True is dispatch_foe("Erons", "Davidemi", "Victor Aiyeola")

The end

And there, little mortal one, is an elegant solution to Isaac's problem. Genghis khan did use Isaac's solution for solving the problem of enemies. Unfortunately, Isaac's name isn't in the history books. Yeah because some organizations and some successful products don't give their engineers enough praise.

It's important to know that the '*' character was introduced by PEP448 and is usually referred to as iterable unpacking operator.

Know also, that the usage of *args and **kwargs (we'll learn this later) can make debugging quite evil. So you'd want to watch your back whilst using them.

Disclaimer

There is no GenghisKhan module implemented anywhere in the Python standard library or Pypi index or anywhere. No murders were committed in the course of this code and my enemies are excellent engineers with happy jobs (I don't have one, so I don't like them at all).

Also, there is no proof that Genghis Khan actually asked Isaac to write this function. I must have written this article while dreaming.

The actual end

May the force of the snaky language dwell richly in your soul and may you find what is that good, pleasing and perfect will of The One Above All.