Slash(/) and Asterisk(*) in Function Definition

Slash(/) and Asterisk(*) in Function Definition

When you read the documentation of some functions you see a slash (/) and an asterisk (*) passed in the function definition. Why are they passed in a function?

Why Slash and Asterisk are Used?

The slash (/) and asterisk (*) are used to determine how an argument should pass when a function is called.

Simply said, the parameters on the left side of the slash (/) must be supplied as positional-only arguments, whereas the parameters on the right side can be passed as either positional or keyword arguments.

An asterisk (*) indicates that the parameters on the right side must be supplied as keyword-only arguments, while the parameters on the left side can be passed as positional or keyword arguments.

def func(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
      -----------    ----------     ----------
        |             |                  |
        |        Positional or keyword   |
        |                                - Keyword only
         -- Positional only
Left-side ParametersSymbolRight-side Parameters
Positional-only arguments/Either positional or keyword arguments
Either positional or keyword arguments*Keyword-only arguments

Slash and Asterisk in Function Parameter

Here's a simple example to show that when slashes and asterisks appear in a function definition, then parameters are bound to positional-only and keyword-only arguments, respectively.

# Normal Function
def func_params(x, y, /, *, z):
    print(x, y, z)

You can conclude that x and y are positional-only parameters, while z is keyword-only. Let's experiment to see if the parameters are bound to positional-only and keyword-only arguments.

params = func_params(2, y=3, z=4)

The parameter x is supplied as a positional argument, while y and z are passed as keywords or named arguments. When you run the code, the following output will be produced.

Traceback (most recent call last):
  ...
    params = func_params(2, y=3, z=4)
             ^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: func_params() got some positional-only arguments passed as keyword arguments: 'y'

Python raises a TypeError indicating that the positional-only argument (y) was given as a keyword argument. If you simply supply y as a positional argument, the code will not generate any errors.

# Normal Function
def func_params(x, y, /, *, z):
    print(x, y, z)

# x & y passed as positional argument and z as a keyword argument
params = func_params(2, 3, z=4)

--------------------
2 3 4

Can Asterisk Be Used Ahead of Slash

The asterisk (*) must come after the slash (/). Now, you may be wondering if this is a rule.

You may think of it as a rule, if you use both a slash and an asterisk, the slash must come before the asterisk, otherwise, Python will throw a syntax error.

# Used asterisk before slash
def func_params(x, y, *, /, z):
    print(x, y, z)

params = func_params(2, 3, z=4)

The code has been modified, and the asterisk is used before the slash. When you run the code, you'll get a syntax error.

  ...
    def func_params(x, y, *, /, z):
                             ^
SyntaxError: / must be ahead of *

Logically inserting an asterisk before the slash doesn't make sense because the parameters on the right side of the asterisk are keyword-only, but the parameters on the left side of the slash are positional-only.

This will not work at all. Here is an example to demonstrate this situation.

# Used asterisk before slash
def func_params(x, y, *, a, b, /, z):
    print(x, y, a, b, z)

params = func_params(2, 3, a=5, b=6, z=4)

The parameters a and b are between the asterisk and the slash, making it unclear if they are positional or keyword-only parameters. This code will still throw a syntax error even after passing a and b as keyword arguments.

Using Either One of Slash (/) or Asterisk (*) in the Function's Parameter?

You can utilise either one depending on the type of parameters you require, whether positional-only or keyword-only. Here's an example showing the use of only a slash (/) in a function definition.

def func_params(pos1, pos2, /, pos_or_kw):
    print(pos1, pos2, pos_or_kw)

params = func_params(2, 3, pos_or_kw=4)

--------------------
2 3 4

The parameters pos1 and pos2 are positional-only parameters and pos_or_kw is a positional-or-keyword parameter.

Similarly, you can use a bare asterisk (*) also in the function definition.

def func_params(pos_or_kw, *, kw1, kw2):
    print(pos_or_kw, kw1, kw2)

params = func_params(4, kw1=3, kw2=2)

--------------------
4 3 2

Writing a Function that Accepts Positional-only Arguments

If you want to create a function or class that only accepts positional arguments, add the slash (/) at the end of the parameter list.

# Function that takes only positional arguments
def prescription(med1, med2, med3, /):
    print("Prescribed Meds:")
    print(f"Med 1: {med1}")
    print(f"Med 2: {med2}")
    print(f"Med 3: {med3}")

prescription("Paracetamol", "Omeprazole", "Ibuprofen")

--------------------
Prescribed Meds:
Med 1: Paracetamol
Med 2: Omeprazole
Med 3: Ibuprofen

The function prescription() takes three arguments: med1, med2, and med3. You can see that a slash (/) is written at the end of the parameters which makes them positional-only.

You'll get an error if you try to pass a keyword argument to the function prescription().

prescription("Paracetamol", "Omeprazole", med3="Ibuprofen")
--------------------
Traceback (most recent call last):
  ...
    prescription("Paracetamol", "Omeprazole", med3="Ibuprofen")
TypeError: prescription() got some positional-only arguments passed as keyword arguments: 'med3'

Writing a Function that Accepts Keyword-only Arguments

You can use a bare asterisk (*) in a function definition to make the parameters on the right side keyword-only.

If you want a function that only accepts keyword parameters, simply include a bare asterisk (*) at the beginning of the function parameter list.

# Function that takes only keyword arguments
def prescription(*, med1, med2, med3):
    print("Prescribed Meds:")
    print(f"Med 1: {med1}")
    print(f"Med 2: {med2}")
    print(f"Med 3: {med3}")

prescription(med1="Paracetamol", med2="Omeprazole", med3="Ibuprofen")

-------------------
Prescribed Meds:
Med 1: Paracetamol
Med 2: Omeprazole
Med 3: Ibuprofen

The function prescription() now only accepts keyword arguments and disallows positional arguments.

Valid & Invalid Function Definitions

Here are some valid function definitions that can go well with slash and asterisk. Source

def f(p1, p2, /, p_or_kw, *, kw):
def f(p1, p2=None, /, p_or_kw=None, *, kw):
def f(p1, p2=None, /, *, kw):
def f(p1, p2=None, /):
def f(p1, p2, /, p_or_kw):
def f(p1, p2, /):

You are most likely familiar with the rules for defining positional and keyword parameters, and the function definitions mentioned above are valid in accordance with those rules.

However, the following function definitions are considered invalid because they aren't defined as per the rules.

def f(p1, p2=None, /, p_or_kw, *, kw):
def f(p1=None, p2, /, p_or_kw=None, *, kw):
def f(p1=None, p2, /):

Once the parameter with default value has been defined, all subsequent parameters (optional for parameters after the asterisk) must be defined with the default value to avoid ambiguity in function calls.

Conclusion

The slash (/) and asterisk (*) determine how an argument should be passed when you call the function.

A slash (/) in the function definition indicates that the parameters on the left side must be treated as positional-only.

A bare asterisk (*) in function definition indicates that the parameters on the right side must be treated as keyword-only.

You can use either both of them or a single in the function definition. When you are using both slash and asterisk, the slash must be inserted before the asterisk.


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

Why if __name__ == "__main__" is used in Python programs?

What is the yield keyword in Python?

Create a WebSocket server and client in Python.

How do decorators in Python work and how to create a custom decorator?

What is __getitem__ method in Python class?

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!