We are excited to introduce our new Python Technical Guidelines.
At Mirai, we are passionate about Python solutions and strive to always keep a keen eye on the best practices in the field. These guidelines are the result of years of applied project experience, refined into actionable insights to help Python developers follow common best practices and write cleaner, more efficient, and maintainable code. We hope this new resource provides you with a clearer pathway to a more robust and Pythonic coding style, and helps you bridge the gap between theoretical knowledge and hands-on expertise.
With our Python Technical Guidelines, we go in-depth on key Python topics, such as:
- the fundamentals of object-oriented programming;
- advanced concepts, like testing frameworks (Pytest) and performance optimization.
The idea behind these guidelines is to keep your code productively organized, and to elevate it such that it meets industry standards, providing a consistent and robust foundation for future maintenance and extension.
In the guidelines, we help you create reproducible environments with different tools, like the ever more popular Pixi. We also delve into how to write concise and clear Python code — which enhances code maintenance — and address the usage of:
- generator expressions
- comprehension
- decorators
- exception handling
These guides covers as well key aspects of object-oriented programming such as:
- inheritance
- polymorphism
- encapsulation
In the test section, we guide you through setting up pytest
and structuring your project such that it allows automatic discovery of tests, following best practices and conventions. We also cover the usage of pytest
fixtures.
Finally, we showcase the importance of well-documented code through docstrings and comments and touch on code styling in accordance to the PEP 8 guidelines.
These guidelines are developed as a Quarto website, deployed to GitHub Pages and accessible at mirai-solutions.ch/py-techguides.
Below are a few illustrative snippets from our guidelines to give you a taste of the content referenced in the guidelines. For a more comprehensive and in-depth understanding, please refer to the related section in the Python Technical Guidelines.
Stay tuned for updates and new chapters, and let’s see if we can grow some roots here!
Use of Decorators
The ‘Decorators’ section provides a detailed explanation of how to define and use decorators in Python.
Decorators are a specific type of higher-order functions, in that they take a function as input and return a function, allowing one to extend or alter the behavior of the input function.
def my_decorator(function):
def wrapper():
# Do something before
print("Before")
result = function()
# Do something after
print("After")
return result
return wrapper
By using the @my_decorator
syntax, you can apply the decorator to the greet
function:
@my_decorator
def greet():
print("Hi")
greet()
This way greet
is now the decorated version of itself, and the output of the function is:
Before
Hi
After
Defining Generators
As shown in the ‘Generators’ section, generators are functions that create a special generator iterator by defining how to yield one element at a time, allowing to hold a state that can be used to yield the value for the next element based on previous ones.
A powerful aspect of generators is that they allow to separate the logic for generating the next element in a sequence from the logic that makes use of the values. To illustrate this, we define a generator function for the Fibonacci sequence:
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
The yield
keyword returns a value and pauses the function’s execution until another value is requested. Values can be retrieved either using next()
or via standard for
iteration.
fibonacci_sequence = fibonacci(6)
print(next(fibonacci_sequence))
print(next(fibonacci_sequence))
print(next(fibonacci_sequence))
print(next(fibonacci_sequence))
print(next(fibonacci_sequence))
print(next(fibonacci_sequence))
0
1
1
2
3
5
for element in fibonacci(6):
print(element)
0
1
1
2
3
5
Generators can be easily converted to lists, but also used in comprehensions or directly as iterators in functions like sum()
.
list(fibonacci(15))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
sum(fibonacci(15))
986
[_ for _ in fibonacci(15) if _ % 2 == 0]
[0, 2, 8, 34, 144]
sum(_ for _ in fibonacci(15) if _ % 2 == 0)
188