Python ** Explained (Double Star or Double Asterix)

by | Python

In Python programming, you may encounter various operators that perform specific operations. One such operator is the double star operator (**). Understanding its function and usage is essential to make the most of your Python programming experience.

The double star operator, denoted by (**), is an arithmetic operator in Python often used for exponentiation. In other words, it’s a power operator that raises the number on its left to the power of the number on its right. It also plays a role in function calls to unpack keyword arguments. By prefixing a dictionary with the ** operator, you can provide keyword arguments to a function based on the dictionary’s key-value pairs.

Recognizing this operator’s purpose will allow you to manipulate and calculate numbers more efficiently in your code. You can also use it to create cleaner and more dynamic code when working with Python dictionaries.

Let’s dive into the various ways you can use the ** operator.

How to Use the Double Star Operator (**) in Python

In Python, the double asterisks have many uses. They find applications in arithmetic operations, function arguments, and dictionary data structures.

Let’s look at these applications:

1. Exponentiation Operations with **

What Does ** Mean in Python?

In Python arithmetic, the double asterisks represent exponentiation, which is a type of arithmetic operation. It allows you to raise a number to the power of another number.

This means that, given two numbers a and b, the expression ‘a**b’ calculates the value of a raised to the power of b. The double star operator is part of Python’s arithmetic operators, which also include addition (+), subtraction (-), multiplication (*), division (/), integer division (//), and modulo (%).

Here’s an example of using the double star operator for exponentiation:

a = 3
b = 2
result = a ** b
print(result)

Output:

9

In this example, a is raised to the power of b, resulting in the value of 9 (3 ** 2). You can also use the double star operator with various numeric data types, such as integers, floats, and complex numbers.

Here’s an example with different data types:

a = 10
b = 2
result1 = a ** b 

a = 1.5
b = 2.5
result2 = a ** b

a = 3 + 2j
b = 3 + 5j
result3 = a ** b

print(result1)
print(result2)
print(result3)

Output:

100
2.7556759606310752
(-0.7851059645317211+2.350232331971346j)

You can also use the pow() function to perform exponentiation:

z = pow(2, 3)
print(z) 

Output:

8

The pow() function takes two arguments: the first argument is the base, and the second argument is the exponent. The function returns the result of raising the base to the power of the exponent, as shown in the example above.

You can read more about the pow() function in this article on How to Square in Python!

Double Asterisk ** Operator Precedence

It’s important to understand the precedence of arithmetic operators in Python when using the double star operator with other arithmetic operators. The order of precedence, from highest to lowest, is as follows:

  1. Exponentiation (**)
  2. Negation ()
  3. Multiplication, Division, Integer Division, and Modulo (*, /, //, %)
  4. Addition and Subtraction (+, )

This means that exponentiation operations will be executed before any other arithmetic operations in an expression.

x = 2 + 3 ** 2
print(x)  

Output:

11

In the above example, the exponentiation operation (3 ** 2) is executed first, resulting in a value of 9. Then, the addition operation (2 + 9) is executed, giving a final result of 11 for x.

When performing complex calculations, it’s better to break down expressions using parentheses. This ensures that Python carries out all operations in the correct order.

We can rewrite the previous example as:

y = (2 + 3) ** 2
print(y)  

Output:

25

In this case, the addition operation (2 + 3) is executed first due to the parentheses, resulting in a value of 5. Then, the exponentiation operation (5 ** 2) is executed, giving a final result of 25 for y.

2. Using ** for Keyword Arguments in Function Definitions

Function Definition

Double asterisks serve another purpose in function definitions and calls. In function definitions, the double asterisk (**) is used before a parameter to collect keyword arguments into a Python dictionary.

Similarly, in function calls, the double asterisk (**) can be used to unpack a dictionary and pass its key-value pairs as keyword arguments to the function. Here is an example:

def example_function(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

parameters = {'param1': 'value1', 'param2': 'value2'}
example_function(**parameters)

Output:

param1: value1
param2: value2

In the above code, the example_function accepts keyword arguments, which are collected inside the kwargs dictionary. When the function is called with the **parameters syntax, the dictionary is unpacked, and its key-value pairs are passed as keyword arguments.

To properly understand the role of the double asterisk operator in a function definition, let’s shed a bit more light on the type of arguments in a function definition:

i. Positional Arguments

In Python, positional arguments are inputs passed to a function in the order in which they are defined in the function definition. For example, consider the following function:

def greet(name, greeting):
    print(f"{greeting}, {name}!")

Here, name and greeting are positional arguments. When you call the function, you provide these arguments in the same order as they appear in the function definition:

greet("John", "Hello")

Output:

Hello, John!

ii. Keyword Arguments

Keyword arguments, also known as named arguments, are function inputs that are identified by the keyword or parameter name they are assigned to. A keyword argument can be passed to a function in any order as long as its parameter name is specified.

Using the same greet function as before, you can call it with keyword arguments like this:

greet(name="John", greeting="Hello")

Python also supports default values for parameters, making them optional when calling the function:

def greet(name, greeting="Hello"):
    print(f"{greeting}, {name}!")

greet("John")    

Output:

Hello, John!

In the example above, we use just one positional argument since we already have a default value for the second positional argument.

iii. *Args and **Kwargs

In Python, you may come across functions that need to accept a variable number of arguments. To handle variable arguments, the special notation *args and **kwargs can be used in the function signature.

*args represents a variable-length list of positional arguments. It allows you to pass any number of positional arguments to the function, which are then collected into a tuple.

For example:

def add_numbers(*args):
    total = 0
    for num in args:
        total += num
    return total

You can call the add_numbers function with any number of arguments:

add_numbers(1, 2, 3)
add_numbers(10, 33, 4, 6 ,7, 7, 28)

Output:

6
95

As we can see, there is no limit to how many arguments we can pass into the function. The function can accept unlimited positional arguments.

**kwargs, on the other hand, is used to collect a variable-length argument dictionary of keyword arguments. It allows you to pass any number of keyword arguments to the function, which are then collected into a dictionary.

For example:

def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

You can call the print_info function with any number of keyword arguments:

print_info(name="John", age=30, city="New York")

Output:

name: John
age: 30
city: New York

In summary, Python functions use positional and keyword arguments when accepting inputs. The special notations args and *kwargs provide flexibility for handling variable-length lists of arguments in function calls. By properly using these features, you can create clean and efficient code that is easy to read and understand.

Keep in mind that the double star operator’s behavior is different depending on its usage, either as an exponentiation operator or as a means to handle keyword arguments in functions.

3. Unpacking Dictionaries with **

In Python, you’ll often come across the double star operator (**) whilst working with dictionaries. You can use the double-star operator to unpack a dictionary.

After unpacking the dictionary, you can pass its key-value pairs as positional arguments to a function. This can be particularly useful when you have a dictionary containing relevant function arguments.

Here’s an example:

def greet(name, age):
    return f"Hello, {name}! You are {age} years old."

person = {'name': 'Alice', 'age': 30}

result = greet(**person)  # equivalent to greet(name='Alice', age=30)
print(result)  # Output: "Hello, Alice! You are 30 years old."

In the code above, the **person syntax unpacks the person dictionary, passing its values as arguments to the greet function call. This makes it easier to work with dictionaries when calling functions.

You can check out this data structure in our article on How To Build A Google News Aggregator In Power BI Using Python.

4. Merging Dictionaries

What Does ** Mean in Python? : Merging Dictionaries

Another handy feature of the double star operator is merging dictionaries. If you have two dictionaries and want to create a new one that contains the items of both, you can use the double star operator in conjunction with dictionary literals. Here’s how:

dict1 = {'a': 1, 'b': 2}
dict2 = {'c': 3, 'd': 4}

merged_dict = {**dict1, **dict2}
print(merged_dict)  

Output:

 {'a': 1, 'b': 2, 'c': 3, 'd': 4}

In the example above, {**dict1, **dict2} unpacks both dictionaries and combines their key-value pairs into a new dictionary. Note that if the dictionaries share keys, the values in the second dictionary will take precedence and overwrite those in the first.

Keep these uses of the double star operator in mind when working with dictionaries in Python, and leverage it to streamline your code and enhance its readability.

Memory and Performance Considerations with the ** Operator

** Memory and Perfomance

The double-star operator (**) operator possesses certain memory and performance attributes that you should be aware of when incorporating it into your code.

When comparing the double-star operator to the built-in pow() function, the former is generally faster and more commonly used. The double-star operator (**), being an arithmetic operator, requires less memory compared to a function like pow().

This is primarily due to the fact that pow() requires additional memory locations for its input parameters.

Consider a scenario where you are working with large data sets or performing numerous calculations. In such a case, the optimal choice for memory and performance would likely be the double-star operator.

The increased efficiency may lead to a more streamlined execution process, potentially reducing the computational burden on your system.

It is crucial, however, to remember that the performance difference between the two choices might not be significant for smaller data sets or basic calculations. Therefore, it is advisable to select the most appropriate approach based on your specific use case.

To summarize, the double-star operator in Python offers some benefits. These benefits include reduced memory consumption and faster execution times, compared to using the pow() function.

Python Version Differences

In Python, the double-star operator (**) is used for exponentiation, where one number is raised to the power of another. This operator is available and functions the same way in both Python 2 and Python 3.

For example, if you want to calculate 2 raised to the power of 3, you would use 2 ** 3, which would return 8. No matter whether you are working in Python 2 or Python 3, this operation would yield the same result.

For instance, consider the following function definition:

def example_function(a, b, **kwargs):
    print(a)
    print(b)
    print(kwargs)

In this case, a and b are positional arguments, and kwargs is a dictionary that stores any additional keyword arguments passed to the function.

Furthermore, this pattern is consistent in both Python 2 and Python 3, so you can use it in your code with confidence, regardless of the version you are working with.

In summary, the double-star operator serves two main purposes in Python:

  1. Exponentiation in mathematical calculations
  2. Allowing functions to accept varying numbers of keyword arguments

These functionalities remain consistent across Python 2 and Python 3, so you can use the double-star operator with confidence, knowing that it functions similarly in both versions of the language.

Final Thoughts

In this tutorial, you have learned about the double-star operator (**) in the Python programming language. By understanding the nuances of the double-star operator, you are better equipped to create clear and efficient code, improving the overall quality of your Python programming.

Remember, the double-star operator is an arithmetic operator used for exponentiation. Additionally, it is used in function definitions to accept a variable number of keyword arguments. When employed in this manner, it provides a concise and clean way of handling keyword arguments in a function, making you a more effective Python developer.

With this newly acquired knowledge, you can be more confident and knowledgeable in your coding endeavors, making your code more robust and efficient. Keep honing your skills, and always remain open to learning new techniques and approaches, as the world of Python programming is vast and constantly evolving!

If this article captures your interest, we encourage you to peruse our article on How to Check if A Dictionary is Empty.

Frequently Asked Questions

What happens if there is a conflict while merging dictionaries with **?

A conflict occurs when one or more keys are present in both of the dictionaries to be merged. In this case, the key in the second dictionary wins out and overwrites the first one in the new, merged dictionary.

For example:

a = {'name': 'John', 'age': 32, 'country': 'Denmark'}
b = {'country': 'United Kingdom', 'city': 'London', 'team':'chelsea'}

c = {**a, **b}
print(c)

Output:

{'name': 'John', 'age': 32, 'country': 'United Kingdom', 'city': 'London', 'team': 'chelsea'}

Both dictionaries contain the key country. In the final merged dictionary, the value for the key corresponds to the value in the second dictionary b.

Are the args, kwargs keywords necessary?

No, they are not necessary. The only syntax compulsory is the single (*) and double asterisks(**). For example, look at these function definitions:

def test_func1(*boo):
    pass

def test_func2(**foo):
    pass

In the functions above, boo will still collect positional arguments and store them in a tuple, while foo will collect keyword-only arguments and store them in a dictionary.

However, it is better to stick to the standard args and kwargs convention to avoid confusion.

Can you use *args and**kwargs together in the same function definition?

Yes, you can use both of them in the same function definition. Here’s an example:

def print_func(*args, **kwargs):
    print(args)
    print(kwargs)

print_func('tea', 'toast', 'bacon', 'eggs', meal = 'breakfast', time='morning')

Output:

('tea', 'toast', 'bacon', 'eggs')
{'meal': 'breakfast', 'time': 'morning'}

We can see that the function captures the non-keyword arguments in a tuple and places the keyword arguments in a dictionary. You can specify positional arguments in the function definition. However, always make sure they are ahead of the *args argument.

Also, ensure that all positional arguments, including *args are always ahead of keyword arguments. For example:

def print_func(meal,*args, **kwargs):
    print(meal)
    print(args)
    print(kwargs)

print_func('breakfast', 'tea', 'toast', time ='morning', 'bacon', 'eggs')

Output:

  Cell In[1], line 6
    print_func('breakfast', 'tea', 'toast', time='morning', 'bacon', 'eggs')
                                                                           ^
SyntaxError: positional argument follows keyword argument

The error occurs because we have the positional arguments bacon and eggs following a keyword argument.

author avatar
Sam McKay, CFA
Sam is Enterprise DNA's CEO & Founder. He helps individuals and organizations develop data driven cultures and create enterprise value by delivering business intelligence training and education.

Related Posts