Table of contents
Text Link
Text Link

Getting the Most from Keywords in Python

In this article, we will discuss keywords and soft keywords in Python: what they are and how to use them. I will introduce you to all the keywords and soft keywords in Python, providing necessary examples.

What are keywords?

Keywords are special words reserved for a specific purpose, and they cannot be used for anything else. For example, def is used when constructing a function. If you try to use this word as a name (identifier, function name, variable name) in your code, you will get a SyntaxError. This means that you attempted an action that is not allowed, and Python prevented you from doing so. The same applies to all keywords. A small exception exists for the words None, True, and False. While you still can't use them as names, you can at least print them! πŸŽ‰ We will learn why later.

‍

What about built-in functions like str or bin? Are these keywords? No, they are not. The list of keywords is well-defined, and we will examine it shortly. Unfortunately, since str is not a keyword, all Pythonistas are destined to encounter str = 'hello 😏' in a beginner's code. 😱

Note: It's worth mentioning that you also can't reassign keywords to other variables. For example, you cannot use T as a keyword instead of class (T = class).

Note: The term 'keyword argument' has nothing to do with keywords. For instance, in complex(real=9, imag=0), real=9 and imag=0 are keyword arguments, meaning that an argument is preceded by an identifier.

Motivation

Knowing the keywords of your language is crucial. They are the building blocks that help you make your dream app a reality. Keywords define the entire flow of your program. Any concept you use or idea you try to implement is related to keywords. Potentially, you could write a program without a keyword, such as a quine c = 'c = %r; print(c %% c)'; print(c % c), but is this the peak of your imagination?

Without keywords, you cannot make your program object-oriented, handle exceptions, control your flow and input, define functions to ease the work, write asynchronous code, use antigravity, and much more.

‍

To fully enjoy and master the language, you must be familiar with its keywords. So, are you ready to explore the keywords that all Pythonistas use every day? If yes, then suit up, and let's go.

‍

Keywords

Python has 35 keywords. For ease of understanding, we can divide all keywords into a few subjective subcategories.

All keywords are case-sensitive, so if the given keyword is True, it works only as True and not as true. Keep this in mind while applying keywords to your code. You can also get a list of all keywords at runtime, ensuring no keyword is overlooked. To view them as a Python list, you can do the following:

import keyword
print(keyword.kwlist)
print(keyword.softkwlist)

For completeness, add keyword.softkwlist to see the soft keywords.

Keywords output:

['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

Soft Keywords output:

['_', 'case', 'match', 'type']

Boolean Manipulations: True, False, not, or, and

The keywords True and False represent boolean values. Many programming languages have human-readable names for these values, and Python is no exception. It's clear that they represent the truth of an expression. Notice that both words are capitalized. Since Python is a case-sensitive language, you must write them exactly as they are. Otherwise, it won't work. One key difference from other keywords (not including None) is that these values are constants. This means that you can use them directly in your code. Let's try it:

print(True)
print(False)

‍

The first line prints True, indicating that the first expression is true, and the second line prints False, indicating that it's not true.

‍

While writing them by themselves might seem pointless, they represent a fundamental concept that you will use with more complex expressions. Let's look at some examples:

print(1 > 2)
print(2 > 1)

The first one evaluates to False, since 1 is not strictly larger than 2, and the second one evaluates to True, since 2 is indeed strictly larger than 1. In both these examples, you see True or False values as your output even if you didn't specify them explicitly.

‍

Simple expressions are not as much fun to look at, so let's try another example and see what it will evaluate to.

print(0 < 1 and 12 + True > 12 or {})

Do you know the result? The result is True.

‍

0 < 1 is True

12 + True > 12 is True

{} is False πŸ˜‰

‍

So, it's True and True or False and it's time to talk about what's going on here in more detail.

‍

and and or represent the boolean operators. They allow you to work with more complex boolean expressions, such that the result depends on multiple criteria.

‍

and evaluates to true if and only if both the left and the right parts of it are true. For example, True and True evaluates to True, True and False evaluates to False, False and True evaluates to False.

‍

or evaluates to true if at least one side of or is true. True or True evaluates to True, True or False evaluates to True, False or True evaluates to True, and False or False evaluates to False.

‍

Note that the chain of execution follows the short-circuit evaluation. In practice, this means that when the minimum condition in the chain is satisfied, the rest of the chain's evaluation is not necessary, so it stops. For example, True or True or True or True or False or …. After the first True, it stops and returns True because it understands that no additional calculations are necessary if one side of the or is True.

‍

Here is one more example: (True or False) and False. In this example, True or False is evaluated first, without evaluating the second operand of the or operator (because it knows that only one part for the or should be true). Next, it evaluates both operands of True and False expression that results in False.

‍

not is nothing else but the negation of the given boolean value.

print(not True)  # False
print(not False)  # True

‍

Even if the concept of True/False and operations on them is simple, Python has a few quirks that one might want to know about.

First, you can use True as the value 1, and False as the value 0. For example, if you need to count the number of expressions that are evaluated to True, you can simply do this (it is a toy example, don't bite me):

sum([True, False, True, False, True, True, False, False])Β  # 4

And yes, you can add them to any other number. 1 + True yields 2. 1 / False raises a ZeroDivisionError 😭

The next behavior that you might not expect is the result of something like this:

print(False or {1})

‍

This prints {1}. The reason is that Python returns the last evaluated part of an expression. While it might look like something awful, in practice it's quite handy. For example:

while some_array:
    do_something

‍

In this case, some_array in a boolean context will be evaluated to True if it has any elements in it. So, no additional checks are needed to stop the while loop.

connection_ip = get_ip() or '127.0.0.1'

‍

In this case, if get_ip() returns None, it's quite handy to set some default value with the help of the or operator.

‍

As a last bit, let's say what values are False when they're treated in a boolean context. As the docs say, the values are - False, None, numeric zero of all types, empty strings and containers (including strings, tuples, lists, dictionaries, sets, and frozen sets). Anything else will be evaluated as True. You can check what is what by doing bool(...).

‍

Pro tip: Since boolean expressions evaluate to a boolean, return the expression instead of doing something like print(True if 'some boolean result' else False). Don't forget that if any other object is involved, it may return that object instead of the plain False/True value.

‍

Pro tip: Use … is True / … is False to check for truthiness explicitly if necessary.

The None Keyword

None is used to represent the absence of a value. Nothing else is like None. It's also returned by default from any function if the return statement is not used. Note that, as with True/False, None is also a capitalized word and a constant. However, even if bool(None) is False, you can't add them together or to anything else (this results in a TypeError). Let's look at some examples:

def foo(arr=None):
    if arr is None:
        arr = []
print(foo())  # None

‍

Here, the function foo doesn't return anything explicitly, and by default, the value None is returned.

The value arr is also set to a default None. In this case, it's recommended to use None, since a list is mutable and may lead to unpredictable results. For example, if you use recursion and want to feed a mutated array for a recursive call.

‍

Pro Tip: As with True/False, it's recommended to use … is None when you need to check if some value is None. For example:

def foo(a):
    if a is None:
        print("It's None. PANIC!!!")
    else:
        print("Just a number.")

‍

In this case, if we pass the value 0 to the function, it won't confuse it with None and will not print that it’s just a number.

‍

For now, you might have recognized some other keywords that we didn't cover. Don't worry, we will talk about them sooner or later.

Conditional Statements: if, elif, else

We've seen some of these at work, but what exactly do they do? These statements are part of the so-called "control flow" of the program. The if and elif statements accept a condition (that can be evaluated as True or False) and execute the first block of code that meets this condition. If no conditions are met, then the else block is executed. The elif and else statements are optional; you can use a single if, if/else, if/elif, if/elif/elif/... or if/elif/else.Β 

Let's look at an example:

age = 30
if age < 15:
    print("You're counting your age in weeks.")
elif age < 25:
    print("You're counting your age in years.")
elif age < 50:
    print("You're counting your age in decades.")
else:
    print("You're timeless.")

‍

In this example, we compare age with a value, which evaluates to True or False. In this case, both age < 15 and age < 25 are False. So we go to the next condition, age < 50, which evaluates to True, so we print You're counting your age in decades. If there were more conditions, or if the first one was evaluated to True, the rest wouldn't be evaluated and it would continue at the next line after the else block.

‍

There's nothing particularly difficult about this, just make sure the syntax is correct (the keyword, a boolean expression, and a colon ":" at the end of the expression) and that all expressions follow logically. For example:

age = 40
if age > 20:
    print('Oh, hello there.')
elif age > 30:
    print('Howdy mate!')
else:
    print('Sup my child.')

‍

Perhaps you intended to print 'Howdy mate!', but because of the flawed logic, you get 'Oh, hello there.' and age > 30 will never be evaluated.

‍

Note: if/elif/else has a one-line shortcut idiom:

age = 20
print('Very young' if age < 18 else 'Still young' if age < 30 else 'Not that young')  # Still young

‍

This is okay to use with short expressions, but it can be quite challenging to read longer ones.

‍

It's important to note that you need to keep your if blocks connected. For example:

age = 30
if age < 15:
    print("You're counting your age in weeks.")
if age < 25:
    print("You're counting your age in years.")
if age < 50:
    print("You're counting your age in decades.")
else:
    print("You're timeless.")

is not the same as

age = 30
if age < 15:
    print("You're counting your age in weeks.")
elif age < 25:
    print("You're counting your age in years.")
elif age < 50:
    print("You're counting your age in decades.")
else:
    print("You're timeless.")

Can you guess why?

Time to Fly: from, import, as

It's not a secret that you can "fly" with Python, as humorously depicted in this XKCD comic.

But what does the import antigravity statement in that comic do? Try it yourself and find out!

‍

The import statement is used to add different external or local modules to your program. This allows you to enhance the functionality of your application without having to implement any complex algorithms yourself. Let's look at some examples.

‍

Have you ever come across the math module? If not, you can simply do the following:

import math
print(math.e, math.pi)

‍

This will import the math module, and you can use its constants and methods from it. It is as simple and easy as it looks.

The import system also supports importing single functions and constants with the help of the from keyword.

from math import gamma, pi, sqrt
print(gamma(1.5))Β  # 0.886226925452758
print(sqrt(pi) / 2)Β  # 0.8862269254527579

‍

If you don't like the imported name, you can use another keyword as to help you with aliases.

from math import gamma, pi, sqrt as square_root
print(gamma(1.5))Β  # 0.886226925452758
print(square_root(pi) / 2)Β  # 0.8862269254527579

‍

Let's enhance this humble description with some best practices, shall we?

  • As demonstrated above, you can import names with your aliases. This helps to avoid name collisions. Remember to set descriptive and meaningful names!
  • Avoid wildcard imports! Polluting the namespace with tons of unused functions is never good for your code.
  • Follow the PEP 8 recommendations to organize your imports.

‍

Share this article
Get more articles
like this
Thank you! Your submission has been received!
Oops! Something went wrong.

Be the Exception: raise, try, except, finally, assert

Python's exception system is a robust mechanism that helps manage all types of errors that your code might encounter. It ensures that you have full control over everything you write, providing stability, and reliability, and it's a significant time saver. Here's an example:

file = None
try:
    file = open('example.txt')
    content = file.read()
    print(content)  # e.g. Hello, world!
except FileNotFoundError as fnf_error:
    # No file found: [Errno 2] No such file or directory: 'example.txt'
    print(f'No file found: {fnf_error}')
except Exception as e:
    print(f'An error occurred: {e}')
else:
    print('File read successfully!')
finally:
    if file is not None:
        file.close()
        print('File closed.')
    print('Always executed.')

‍

In this example, we're using the exception-handling mechanism to its fullest. The try block attempts to open a file named 'example.txt'. If the file doesn't exist, it will throw an exception. The FileNotFoundError is caught in the except statement. Note that you are given a handy alias fnf_error for the exception. You can extract information from the fnf_error object and take control of it. In this case, we're just printing the object. If any other exception occurs, we will catch it with the except Exception as e block. Here, we also have full control over the exception. The else block is something that you might not expect to see. The else block is executed if no exceptions occur. Finally, the finally block! This block is always executed. If you have some unfinished business, or if you want to clean up your code, feel free to use the finally block.

‍

Note that else and finally blocks are optional; you can use both of them, only one of them, or none at all.

Another possibility is to use try/finally pair. Let's look at an example that demonstrates that the finally block always executes:

def foo():
    try:
        return True
    finally:
        return False
print(foo())

‍

What do you think is the result of the function? At first glance, you might think that it prints True or even None. That's a reasonable guess. However, remember that finally always executes! And it executes return False, so it prints False. It might look counterintuitive at first, but you need to understand that, unless there are some extraordinary circumstances, the finally block is always the last to execute!

‍

Exception handling has a newer syntax that allows you to handle multiple exceptions in groups. Let's look at an example from the documentation:

def f():
    raise ExceptionGroup(
        "group1",
        [
            OSError(1),
            SystemError(2),
            ExceptionGroup(
                "group2",
                [
                    OSError(3),
                    RecursionError(4)
                ]
            )
        ]
    )

try:
    f()
except OSError as e:
    print("There were OSErrors")
except SystemError as e:
    print("There were SystemErrors")

This is the output:

+ Exception Group Traceback (most recent call last):
|   File "main.py", line 18, in <module>
|     f()
|   File "main.py", line 2, in f
|     raise ExceptionGroup(
| ExceptionGroup: group1 (3 sub-exceptions)
+-+---------------- 1 ----------------
| OSError: 1
+---------------- 2 ----------------
| SystemError: 2
+---------------- 3 ----------------
| ExceptionGroup: group2 (2 sub-exceptions)
+-+---------------- 1 ----------------
   | OSError: 3
   +---------------- 2 ----------------
   | RecursionError: 4
   +------------------------------------

You can refer to the official documentation for a detailed explanation; this example serves as a syntax demonstration with the try/except keywords.

‍

Pro tip: try/except is a time saver. At first, it feels wrong when you do it, but handling some data validation inside of the try/except is a common Python practice and an idiom. Don't be shy, save your time with a try/except block.

‍

Another keyword that fits perfectly in this subsection is the raise statement. You might already guessed what it does - it raises exceptions! Whenever you encounter a situation where you feel it's appropriate to raise an exception, you should do so. Here's a simple example:

x = -1
if x < 0:
    raise Exception('Negative numbers are a lie!')

‍

In this case, you're implicitly raising the Exception. You can handle it right away, but is there a point in doing so?

As you can see, the syntax for this is simple. First, you use raise, then you specify the class of the Exception, and finally, you specify the message to the user. You can also use the single raise statement. It's used to re-raise the previous exception. If no exception occurs, you will get RuntimeError: No active exception to re-raise.

‍

Last but not least is the assert statement:

assert 0 == 1, 'Something is funny with this math'Β  
# AssertionError: Something is funny with this math

‍

The assert statement allows you to check if conditions evaluate to True at some crucial point in your code. assert statements are useful for debugging, and you should never use them in production code.

The syntax for that is as follows: first, the assert keyword, then the boolean expression. If the expression evaluates to False, it throws an AssertionError. The useful message is optional, and you can avoid it if you know what you're doing. Note, that as this is a boolean, you can mix any complex chain as you desire.

Create and control the loop: for, while, continue, break

The for loop is a crucial building block of the Python language. With a for loop, you can iterate over any sequence (lists, tuples, strings, ranges) or anything iterable.

Many languages have a for loop. The classic example of the for loop is something like this:

for i in range(len(arr)):
    print(f'Element #{i+1}: {arr[i]}')

‍

However, Python is not Python without cool syntactic sugar. As you remember, you can iterate over any iterable, so why not just iterate over a list?

for element in arr:
    print(element)

‍

If you want to keep counting, you can always enhance it with an enumerate function.

for count, element in enumerate(arr, start=1):
    print(f'Element #{count}: {element}')

‍

You can always break out of the loop with a break statement. Let's say your mission is to find an element in an array, and you don't want to waste CPU power on iterating the whole array if you've already found the magic element.

for i in range(10**255):
    print(i)
    if i == 5:
        break

‍

In this case, you will see numbers from 0 to 5 (inclusive) printed on your screen.

If you want, you can add an else clause! What? With the loop? You might ask. Yes! With a loop! The else clause is executed only if the whole iterable is exhausted. For example:

for i in range(10):
    print(i)
else:
    print('Hello')

‍

Since we went through all elements of an iterable, the message 'Hello' will be printed at the end. However, if you break and quit the loop before it's exhausted, no message will be printed.

The continue statement is used in the loop if you want to skip some specific position or element or for any other reason you might have in mind.

for i in range(10):
    if i == 5:
        continue
    print(i)

‍

In this case, the number 5 is not going to be printed.

The while loop is similar to the for loop, with the exception that it stops if the provided boolean expression is not true.

while (msg := input()) != 'stop':
    if msg == 'magic':
        print(f'With {msg!r}, you can take a break.')
        break
    print(f'I wrote {msg!r}, but I really need to stop.')
else:
    print('I stopped')

‍

Here's the output:

>>> hello, world
I wrote 'hello, world', but I really need to stop.
>>> 123
I wrote '123', but I really need to stop.
>>> magic
With 'magic', you can take a break.

‍

The else statement works similarly with while loops. The else clause is triggered if the loop exits because the boolean expression is False.

The pass statement

The pass statement is one of the simplest keywords; it acts as a no-op and can be added to any block of code. You can use it as a placeholder if you want to finish something later.

def bar():
    pass

‍

Note: The pass statement is a no-op operation. It doesn't act as break, continue, or return. After the interpreter reads it, it continues to read the next line, as if nothing happened. Indeed, nothing happened!

Working with functions: def, return, yield, lambda

Let's explore the world of functions a bit closer. We've seen some previous examples that used some of these words, for example, def. The def keyword is the syntax to define a function in your code. It serves this purpose and nothing else. To define a function, just write def followed by the name of the function, parentheses (zero or more arguments), and a colon. Don’t forget to pay attention to the indentation inside of the function body.

You might want to use pass if you don't know what the function is for and would like to come back to it later.

def foobar():
    pass

‍

The function is quite useless at the moment, so let's make another one that adds two numbers.

def add(x, y):
    return x + y
    print('You will never see me!')

‍

As you can see, we use the return statement to return the result of our mathematical expression.

In this example, return is the last statement that is processed in the function; nothing after that matters.

def foo(bar):
    if bar < 0:
        return 'negative'
    elif bar == 0:
        return 'zero'
    else:
        return 'positive'

‍

In such an example, the third return is unnecessary, since else is executed no matter what.

It may make a lot of sense to define your function like this instead:

def foo(bar):
    if bar < 0:
        return 'negative'
    elif bar == 0:
        return 'zero'
    return 'positive'

‍

Another way to return a value from the function is to use yield (yield from).

def foo(msg):
    yield from msg

text = foo('Hello there')
print(next(text))  # H
print(next(text))  # e
print(next(text))  # l
print(next(text))  # l
print(next(text))  # o

‍

Yield creates a generator from the function that makes it possible to retrieve a single value at a time.

The last thing about functions is that you can use the lambda keyword to create anonymous functions (the possibility to bind it to a name still exists tho).

text = (lambda msg: (yield from msg))('Hello there')

If we repeat print statements from the previous example, we will get the same result. Of course, this is not a definitive guide on functions, so if you want to learn more about it please refer to documentation or some external resources.

The class keyword

As you might have guessed, the keyword class is used to create your custom objects and enhance your code with an object-oriented style.

class MyClass:
    pass

‍

Here you go, using the keyword class and a name, we created a custom class for creating our objects. Unfortunately, this class does nothing. In some circumstances, you might need it, but let's enhance it just for now:

class MyClass:
    wow = 'Hello, world!'
    
    def greet(self):
        return 'Hello, world!'

mc = MyClass()
print(mc.wow)
print(mc.greet())

‍

As you can see, a single keyword opens the door to a whole new paradigm. To learn more about classes, you might refer to this documentation.

The world of asynchronous programming: async/await

These keywords are used for handling asynchronous programming, which is the concurrent execution of different subroutines. It may lead to increased performance, more efficient use of resources, etc. Here is a simple example:

import asyncio

async def main():
    print('hello')
    await asyncio.sleep(1)
    print('world')

asyncio.run(main())

‍

The async keyword is used to declare a function as a coroutine (you can learn more about it here), which makes it a special kind of function that you can't simply invoke. In this example, I use asyncio.run to invoke the function.

The await keyword is used inside an async function and waits until the completion of any awaitable object. In this example, we use the awaitable sleep method from asyncio and pause the function execution for 1 second. After that, the function continues its execution.

Choose your scope: global, nonlocal

These two keywords are used as helpers to decide which names to refer to in the current scope. Let's look at a simple example:

‍

x = 'global'

def outer():
    x = 'nonlocal'
    
    def inner():
        nonlocal x
        x = 'changed with nonlocal'
    
    inner()
    print(f'nonlocal: {x}')

outer()
print(f'global: {x}')
# nonlocal: changed with nonlocal
# global: global

‍

In this example, we have three variables named x, inside the inner function, we use nonlocal x to set the scope to a non-global scope. That's any scope 'above' the local and not global is treated as nonlocal. Hence the output, the global x is the same, and the non-global x has changed.

If you change nonlocal x to global x, then the opposite will happen; the only x that will be changed is global, and the non-global x (inside the outer function) will stay the same.

The mighty four: del, in, is, with

Ok, last but not least, the mighty four keywords that I couldn't group with any other. πŸ˜…

The del statement is used to delete objects. For example:

x = True
print(x)  # True
del x
print(x)  # NameError: name 'x' is not defined

‍

As you can see, it removes the whole variable, not just nullifies the value.

x = [1, 2, 3, 4, 5]
del x[2]
print(x)  # [1, 2, 4, 5]

‍

In this example, we remove the value at the 2nd index of the array x.

Probably one of the most useful examples is removing a key from a dictionary.

d = {'a': 1, 'b': 2, 'c': 3}
del d['b']
print(d)  # {'a': 1, 'c': 3}

‍

The in operator checks if the target value is in some collection. For example:

word = 'hello, world'
print('Is letter a in the string:', 'a' in word)
print('Is letter a not in the string:', 'a' not in word)

set_ = {1, 2, 3, 4, 5}
print('Is 3 in the set:', 3 in set_)

d = {'a': 1, 'b': 2, 'c': 3}
print('Is x in the dictionary:', 'x' in d)

‍

Output:

Is letter a in the string: False
Is letter a not in the string: True
Is 3 in the set: True
Is x in the dictionary: False

‍

As you can see, you can easily test for membership without writing a custom algorithm for that.

Quick quiz, what do you think? Is it a fast operation to check if some number is in the range or not, and why?

Test your intuition with this simple snippet

print(10 ** 555 // 2 in range(10 ** 555))

‍

The is operator tests for the objects' identity. It's equivalent to id(obj1) == id(obj2).

The preferred usage for is is with the None constant, as shown above in the part about None.

If you want to compare two values, use == instead of is.

a = [1]
b = [1]
print(a is b)  # False

print(None is None)  # True

a = [1, 2, 3]
b = a
print(a is b)  # True

‍

One may say that the with statement creates a context manager. That is, it delegates some functionality to a manager. It ensures that resources are acquired safely before entering the block and released reliably afterward, even if exceptions occur. One of the classic examples is reading a file. The old way is something like this:

file = open('example.txt')
content = file.read()
print(content)
file.close()

‍

In this example, we explicitly closed the file. However, with a context manager, files are closed automatically. It's also more readable and pleasant.

with open('example.txt') as file:
    print(file.read())

‍

To be able to use this with your custom classes, you need to define __enter__() and __exit__() magic methods for your class!

‍

That's it for the main keywords. Next on the menu are soft keywords.

‍

Soft keywords

In Python, soft keywords are something even more special. If you reassign them, they don't throw an exception as with regular keywords. Moreover, in daily life, most Python programmers use one of these as a name for their variable. So, let's begin.

The soft keyword that is often used as a throwaway variable is _. If you don't want to use some variable, you set the name as _.

for _ in range(5):
    print('Hello. Are you there?')

What makes it a soft keyword? The answer to this is context. In Python 3.10, Python introduced structural pattern matching, where three soft keywords are used. Let's take an example and try to explain what each one is doing.

The match statement

def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 404:
            return "Not found"
        case 418:
            return "I'm a teapot"
        case _:
            return "Something's wrong with the internet"

Here we see three of the keywords in use. It works similarly to Rust's pattern matching. The match statement operates on the matching subject (in this case it is status), trying to match it with one of the given cases. Based on the provided input, it should match with the correct block. If none are matched, the wildcard (_) block is executed. The whole topic is much more interesting and contains a handful of tools for your coding journey, so I recommend getting familiar with it.

Type statement

The last one, probably not that well-known at the moment, is the type statement. Attention: not the function, the statement. Here is an example:

type Point = tuple[float, float]
type ListOrSet[T] = list[T] | set[T]

‍

This is simply type aliases for more complex structures. It allows you to define a name before it appears in code. As you can see, it supports generic types as well. Remember value: int = 2? Well, now you can do point: Point before you even define this class!

If you want to learn more about type hints please refer to this pep.

‍

Wrap up

I hope you've gotten a hang of keywords and soft keywords. I tried to elaborate more on the ones that people make more mistakes with, and provided a shorter description for simpler or newer keywords. As no single article is complete (and no one wants to read 37 articles in one πŸ™ƒ), I recommend you go deeper with a keyword that you're most interested in and learn more about it. Have you applied type aliases in your code yet? What about the match statement? It looks very promising.

Good luck on your coding journey and using new keywords in your code!

Create a free account to access the full topic

Wide range of learning tracks for beginners and experienced developers
Study at your own pace with your personal study plan
Focus on practice and real-world experience
Andrei Maftei
It has all the necessary theory, lots of practice, and projects of different levels. I haven't skipped any of the 3000+ coding exercises.