Skip to content

19 Python Syntax Sugars - demo & example

homepage-banner

It’s one thing to make a function work, but it’s another to implement it with precise and elegant code. As the Zen of Python states, “beautiful is better than ugly.” Python, being a powerful programming language, offers various syntax sugars to assist developers in writing elegant code effortlessly.

This article showcases 19 essential syntax sugars in Python that can significantly enhance your coding experience. Mastery of these sugars involves understanding and skillfully utilizing their power.

Enough talking, let’s dive into the code!

1. Union Operators: The Most Elegant Way To Merge Python Dictionaries

There are several approaches to merging multiple dictionaries in Python, but none of them could be described as elegant until the release of Python 3.9.

For instance, how could we merge the following three dictionaries prior to Python 3.9?

One of the methods is to use for loops:

cities_us = {'New York City': 'US', 'Los Angeles': 'US'}
cities_uk = {'London': 'UK', 'Birmingham': 'UK'}
cities_jp = {'Tokyo': 'JP'}

cities = {}

for city_dict in [cities_us, cities_uk, cities_jp]:
    for city, country in city_dict.items():
        cities[city] = country

print(cities)
# {'New York City': 'US', 'Los Angeles': 'US', 'London': 'UK', 'Birmingham': 'UK', 'Tokyo': 'JP'}

It is decent, but far from elegant and Pythonic.

Python 3.9 introduced the union operators, which are a syntax sugar that has made merging tasks super straightforward:

cities_us = {'New York City': 'US', 'Los Angeles': 'US'}
cities_uk = {'London': 'UK', 'Birmingham': 'UK'}
cities_jp = {'Tokyo': 'JP'}

cities = cities_us | cities_uk | cities_jp

print(cities)
# {'New York City': 'US', 'Los Angeles': 'US', 'London': 'UK', 'Birmingham': 'UK', 'Tokyo': 'JP'}

As shown in the above program, we can use the union operators, also known as pipe symbols, to merge multiple Python dictionaries together.

Is it possible to perform an in-place merge using the union operators?

cities_us = {'New York City': 'US', 'Los Angeles': 'US'}
cities_uk = {'London': 'UK', 'Birmingham': 'UK'}
cities_jp = {'Tokyo': 'JP'}

cities_us |= cities_uk | cities_jp
print(cities_us)
# {'New York City': 'US', 'Los Angeles': 'US', 'London': 'UK', 'Birmingham': 'UK', 'Tokyo': 'JP'}

To achieve this, simply move the union operators to the left of the equals sign, as demonstrated in the code above.

2. Type Hints: Making Your Python Programs Type Safe

Dynamic typing, which means determining the type of a variable during runtime, is a key feature that makes Python flexible and convenient. However, it can also lead to hidden bugs and errors if variables are not properly typed.

To address this issue, Python introduced the typing hint feature in version 3.5. It provides a way to annotate variable types in code, and modern IDEs can catch type errors early for developers during the development process.

For example, if we define a variable as an integer but change it to a string, the IDE (PyCharm in this case) will highlight the unexpected code for us.

PyCharm highlights unexpected assignments based on type hints.

In addition to primitive types, there are also some advanced type hint tricks.

For example, it is a common convention in Python to define constants using all capital letters.

DATABASE = 'MySQL'

However, it’s just a convention and no one can stop you from assigning new values to this “constant”.

To improve it, we can use the Final type hint, which indicates that a variable is intended to be a constant value and should not be reassigned:

from typing import Final
DATABASE: Final = "MySQL"

If we make changes to the “constant”, the IDE will definitely remind us.

PyCharm highlights the code that modifies a constant.

3. F-Strings: A Pythonic String Formatting Approach

Python offers several string formatting techniques, including C-style formatting using % symbols, the built-in format() function, and f-strings.

If you are using Python 3.6 or newer, f-strings are the most Pythonic way to format strings. They allow you to perform all formatting tasks with minimal code and even evaluate expressions within strings.

from datetime import datetime

today = datetime.today()

print(f"Today is {today}")
# Today is 2023-03-22 21:52:29.623619

print(f"Today is {today:%B %d, %Y}")
# Today is March 22, 2023

print(f"Today is {today:%m-%d-%Y}")
# Today is 03-22-2023

As demonstrated in the code above, there are only two steps to follow when using f-strings:

  1. Add the letter “f” before the string to indicate that it is an f-string.
  2. Use curly braces with the variable name and an optional format specifier inside the string ({variable_name:format}) to interpolate the variable’s value in a specific format.

The f-strings embody the principle of “Simple is better than complex,” as stated in the Zen of Python.

Furthermore, we can directly execute an expression inside an f-string.

from datetime import datetime

print(f"Today is {datetime.today()}")
# Today is 2023-03-22 22:00:32.405462

4. Use an Ellipsis as a Placeholder for Unwritten Code

In Python, the pass keyword is often used as a placeholder for unwritten code. However, another option is to use an ellipsis for this purpose.

def write_an_article():
    ...

class Author:
    ...

Guido van Rossum, the father of Python, added this syntax sugar to Python because he thought it’s cute (https://mail.python.org/pipermail/python-3000/2008-January/011793.html).

5. Decorators in Python: A Way To Modularize Functionalities and Separate Concerns

Decorators in Python provide a way to add new functionality to an existing object without modifying its original logic.

We can define our own decorators, and there are also many useful built-in decorators available for use.

For instance, static methods in a Python class are not bound to an instance or a class. They are included in a class because they logically belong there.

To define a static method, we simply use the @staticmethod decorator, as shown below:

class Student:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name
        self.nickname = None

    def set_nickname(self, name):
        self.nickname = name

    @staticmethod
    def suitable_age(age):
        return 6 <= age <= 70

print(Student.suitable_age(99)) # False
print(Student.suitable_age(27)) # True
print(Student('yang', 'zhou').suitable_age(27)) # True

6. List Comprehension: Creating a List in One Line of Code

Python is well-known for its conciseness, thanks in large part to its well-designed syntax sugar, such as list comprehension.

List comprehension allows us to combine for loops and if conditions into a single line of code to generate a Python list:

Genius = ["Yang", "Tom", "Jerry", "Jack", "tom", "yang"]
L1 = [name for name in Genius if name.startswith('Y')]
L2 = [name for name in Genius if name.startswith('Y') or len(name) < 4]
L3 = [name for name in Genius if len(name) < 4 and name.islower()]
print(L1, L2, L3)
# ['Yang'] ['Yang', 'Tom', 'tom'] ['tom']

Furthermore, Python also provides set, dictionary, and generator comprehensions. Their syntax is similar to list comprehension.

For example, the following program demonstrates the use of dict comprehension to generate a dictionary based on certain conditions:

Entrepreneurs = ["Yang", "Mark", "steve", "jack", "tom"]
D1 = {id: name for id, name in enumerate(Entrepreneurs) if name[0].isupper()}
print(D1)
# {0: 'Yang', 1: 'Mark'}

7. Lambda Functions for Defining Small Anonymous Functions

The lambda function, also known as an anonymous function, is a syntax shortcut in Python that allows you to define small functions quickly, making your code more concise and readable.

One common use of lambda functions is to define the comparison method for the built-in sort() function:

leaders = ["Warren Buffett", "Yang Zhou", "Tim Cook", "Elon Musk"]
leaders.sort(key=lambda x: len(x))
print(leaders)
# ['Tim Cook', 'Yang Zhou', 'Elon Musk', 'Warren Buffett']

IIn the example above, a lambda function is defined to sort a list based on the length of its elements. The lambda function takes a variable and returns its length. Although we could write a full function in the conventional way, using a lambda function is shorter and cleaner for this simple task.

8. Ternary Conditional Operators: Combining If and Else in a Single Line of Code

Several programming languages support ternary conditional operators. In Python, you can achieve this by combining the if and else statements on the same line:

short_one = a if len(a) < len(b) else b

If we implement the same logic as the above without using ternary condition syntax, we would need a few additional lines of code.

short_one = ''
if len(a) < len(b):
    short_one=a
else:
    short_one=b

9. Use the “Enumerate” Method to Iterate Lists Elegantly

In some cases, we need to access both the index and values of elements in a list when iterating through it.

A classic C-style approach for achieving this looks like the following:

for (int i = 0; i < len_of_list; i++) {
        printf("%d %s\n", i, my_list[i]);
    }

We can write a similar logic in Python, but the my_list[i] syntax seems a bit cumbersome, especially when we need to access the value of the element multiple times.

The more Pythonic way to achieve this is by using the enumerate() function, which allows us to directly retrieve both the index and values:

leaders = ["Warren", "Yang", "Tim", "Elon"]
for i,v in enumerate(leaders):
    print(i, v)
# 0 Warren
# 1 Yang
# 2 Tim
# 3 Elon

10. Context Manager: Closing Resources Automatically

As we know, it is important to promptly close a file after it has been opened and processed in order to free up memory resources. Neglecting to do so can result in memory leaks or even crashing our system.

f = open("test.txt", 'w')
f.write("Hi,Yang!")
# some logic here
f.close()

Handling files in Python is relatively easy. As shown in the code above, we just need to remember to call the f.close() method to free up memory.

However, as programs become more complex and larger, it can be challenging to always remember this. That’s why Python provides the context manager syntax sugar.

with open("test.txt", 'w') as f:
    f.write("Hi, Yang!")

As shown above, the “with” statement is crucial for using context managers in Python. When we open a file using the “with” statement and handle the file within its scope, the file will be automatically closed after processing.

11. Fancy Slicing Tricks for Python Lists

It is often necessary to retrieve a portion of items from a list. In Python, the slice operator has three components:

a_list[start:end:step]
  • “start”: The starting index (default value is 0).
  • “end”: The ending index (default value is the length of the list).
  • “step”: Defines the step size when iterating over the list (default value is 1).

With these parameters, there are a few tricks that can make our code much cleaner.

Reverse a list using a slicing trick

Since slicing operators can accept negative numbers (-1 refers to the last item, and so on), we can take advantage of this feature to reverse a list in the following way:

a = [1,2,3,4]
print(a[::-1])
# [4, 3, 2, 1]

Obtain a shallow copy of a list

>>> a = [1, 2, 3, 4, 5, 6]
>>> b = a[:]
>>> b[0]=100
>>> b
[100, 2, 3, 4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]

The b=a[:] is different from b=a because it assigns a shallow copy of a instead of a itself. As a result, any changes made to b will not affect a as demonstrated above.

12. Walrus Operator: Assignments within Expressions

The walrus operator, also known as the assignment expression operator, was introduced in Python 3.8 and is represented by the := symbol.

It allows you to assign values to variables within an expression, rather than assigning them separately.

For example, consider the following code:

while (line := input()) != "stop":
    print(line)

In this code, the walrus operator (:=) is used to assign the value of the user input to the variable line, while also checking whether the input is “stop”. The while loop will continue to run as long as the user input is not “stop”.

By the way, the walrus operator, :=, got its name from the eyes and tusks of a walrus:

Image from Wikipedia

13. Continuous Comparisons: A More Natural Way To Write If Conditions

In languages like Java or C, there are situations where you need to write if conditions like the following:

if (a > 1 && a < 10){
  //do somthing
}

However, if you are not using Python, you will not be able to write it as elegantly as the following:

if 1 < a < 10:
    ...

Yes, Python allows us to write continuous comparisons, which makes our code appear as natural as the way we write it in mathematics.

14. Zip Function: Combine Multiple Iterables Easily

Python provides a built-in function called zip() that takes two or more iterables as arguments and returns an iterator that combines elements from the iterables.

For example, using the zip() function, you can easily aggregate three lists into one without needing any loops.

id = [1, 2, 3, 4]
leaders = ['Elon Mask', 'Tim Cook', 'Bill Gates', 'Yang Zhou']
sex = ['male', 'male', 'male', 'male']
record = zip(id, leaders, sex)

print(list(record))
# [(1, 'Elon Mask', 'male'), (2, 'Tim Cook', 'male'), (3, 'Bill Gates', 'male'), (4, 'Yang Zhou', 'male')]

15. Swapping Two Variables Directly

Swapping two variables is often one of the first programs a beginner writes after printing “Hello world!”.

The traditional approach in many programming languages involves using a temporary variable to store the value of one of the variables.

For example, you can swap two integers in Java using the following method:

int a = 5;
int b = 10;
int temp = a;
a = b;
b = temp;
System.out.println("a = " + a); // Output: a = 10
System.out.println("b = " + b); // Output: b = 5

In Python, the syntax is intuitive and elegant.

a = 10
b = 5
a, b = b, a
print(a, b)
# 5 10

16. Destructuring Assignment Tricks

Destructuring assignments in Python allow you to assign the elements of an iterator or a dictionary to individual variables. This feature helps you write shorter and more readable code by eliminating the need to access individual elements using indexes or keys.

person = {'name': 'Yang', 'age': 30, 'location': 'Mars'}
name, age, loc = person.values()
print(name, age, loc)
# Yang 30 Mars

As shown in the example above, we can assign the values of a dictionary to three individual variables in a single line of code.

However, if there are only two variables on the left side, how can we receive the assignments?

Python provides another syntax sugar for this situation:

person = {'name': 'Yang', 'age': 30, 'location': 'Mars'}
name, *others = person.values()
print(name, others)
# Yang [30, 'Mars']

As shown above, we can simply add an asterisk before a variable to let it receive all remaining variables from the person.values().

Simple and elegant, isn’t it?

17. Iterables Unpacking with Asterisks

In addition to being used in destructuring assignments, asterisks in Python can also be used for iterable unpacking.

A = [1, 2, 3]
B = (4, 5, 6)
C = {7, 8, 9}
L = [*A, *B, *C]
print(L)
# [1, 2, 3, 4, 5, 6, 8, 9, 7]

As shown above, the easiest way to combine a list, a set, and a tuple into one list is by unpacking them using asterisks within the new list.

18. Any() and All() Functions

In certain situations, we may need to check whether any or all elements in an iterable (such as a list, tuple, or set) are true.

While we can use for loops to check them one by one, Python provides two built-in functions, any() and all(), to simplify the code for these operations.

For example, the following program uses all() to determine if all elements of a list are odd numbers:

my_list = [3, 5, 7, 8, 11]
all_odd = all(num % 2 == 1 for num in my_list)
print(all_odd)
# False

The code below uses the any() function to check if there is a leader whose name starts with “Y”:

leaders = ['Yang', 'Elon', 'Sam', 'Tim']
starts_with_Y = any(name.startswith('Y') for name in leaders)
print(starts_with_Y)
# True

19. Underscores in Numbers

Counting the number of zeros in a large number can be a headache.

Fortunately, Python allows underscores to be included in numbers to improve readability.

For instance, instead of writing 10000000000, we can write 10_000_000_000 in Python, which is much easier to read.

Reference

  • https://medium.com/techtofreedom/19-sweet-python-syntax-sugar-for-improving-your-coding-experience-37c4118fc6b1
  • https://docs.python.org/3/reference/index.html
  • https://mail.python.org/pipermail/python-3000/2008-January/011793.html
Leave a message