{"id":2697,"date":"2025-03-28T07:02:23","date_gmt":"2025-03-28T07:02:23","guid":{"rendered":"https:\/\/mailitics.com\/index.php\/2025\/03\/28\/data-science-from-school-to-work-part-iii\/"},"modified":"2025-03-28T07:02:23","modified_gmt":"2025-03-28T07:02:23","slug":"data-science-from-school-to-work-part-iii","status":"publish","type":"post","link":"https:\/\/mailitics.com\/index.php\/2025\/03\/28\/data-science-from-school-to-work-part-iii\/","title":{"rendered":"Data Science: From School to Work, Part III"},"content":{"rendered":"<p>    Data Science: From School to Work, Part III<br \/>\n \t<BR><br \/>\n<BR><\/BR><br \/>\n    <!-- no image --><br \/>\n \t<BR><br \/>\n<BR><\/BR><\/p>\n<div>\n<h2 class=\"wp-block-heading\"><strong>Introduction<\/strong><\/h2>\n<p class=\"wp-block-paragraph\">Writing code is about solving problems, but not every problem is predictable. In the real world, your software will encounter unexpected situations: missing files, invalid user inputs, network timeouts, or even hardware failures. This is why handling errors isn\u2019t just a nice-to-have; it\u2019s a critical part of building robust and reliable applications for production.<\/p>\n<p class=\"wp-block-paragraph\">Imagine an e-commerce website. A customer places an order, but during the checkout process, a database connection issue occurs. Without proper <a href=\"https:\/\/towardsdatascience.com\/tag\/error-handling\/\" title=\"Error Handling\">Error Handling<\/a>, this issue could cause the application to crash, leaving the customer frustrated and the transaction incomplete. Worse, it might create inconsistent data, leading to even bigger problems down the line. Thus, error handling is a fundamental skill for any Python developer who wants to write code for production.<\/p>\n<p class=\"wp-block-paragraph\">However, good error handling also goes hand in hand with a good logging system. It\u2019s rare to have access to the console when the code is running in production. So there\u2019s no chance of your print being seen by anyone. To ensure that you can monitor your application and investigate any incidents, you need to set up a logging system. This is where the <a href=\"https:\/\/loguru.readthedocs.io\/en\/stable\/api\/logger.html\">loguru<\/a> package comes into play, which I will introduce in this article.<\/p>\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-dotted\">\n<h2 class=\"wp-block-heading\"><strong>I \u2013 How to handle Python errors?<\/strong><\/h2>\n<p class=\"wp-block-paragraph\">In this part I present the best practices of error handling in <a href=\"https:\/\/towardsdatascience.com\/tag\/python\/\" title=\"Python\">Python<\/a>, from try-except blocks and the use of <code>raise<\/code> to the <code>finally<\/code><em> <\/em>statement. These concepts will help you write cleaner, more maintainable code that is suitable for a production environment.<\/p>\n<h3 class=\"wp-block-heading\">\n<strong>The <\/strong><strong><em>try-expect<\/em><\/strong><strong> blocks<\/strong><br \/>\n<\/h3>\n<p class=\"wp-block-paragraph\">The try-except block is the main tool for handling errors in Python. It allows you to catch potential errors during code execution and prevent the program from crashing.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">def divide(a, b):\n\u00a0 try:\n\u00a0 \u00a0 return a \/ b\n\u00a0 except ZeroDivisionError:\n\u00a0 \u00a0 print(f\"Only Chuck Norris can divide by 0!\")<\/code><\/pre>\n<p class=\"wp-block-paragraph\">In this trivial function, the try-except block allows the error caused by a division by 0 to be intercepted. The code in the try block is executed, and if an error occurs, the except block checks whether it is a <code>ZeroDivisionError<\/code> and print a message. But only this type of error is caught. For example, if <em>b<\/em> is a string, an error occurs. To avoid this, you can add a <code>TypeError<\/code>. So, it is important to test all possible errors.<\/p>\n<p class=\"wp-block-paragraph\">The function becomes:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">def divide(a, b):\n\u00a0 \u00a0 try:\n\u00a0 \u00a0 \u00a0 \u00a0 return a \/ b\n\u00a0 \u00a0 except ZeroDivisionError:\n\u00a0 \u00a0 \u00a0 \u00a0 print(f\"Only Chuck Norris can divide by 0!\")\n\u00a0 \u00a0 except TypeError:\n\u00a0 \u00a0 \u00a0 \u00a0 print(\"Do not compare apples and orange!\")<\/code><\/pre>\n<h3 class=\"wp-block-heading\"><strong>Raise an exception<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">You can use the raise statement to manually raise an exception. This is useful if you want to report a user-defined error or impose a specific restriction on your code.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">def divide(a, b):\n\u00a0 \u00a0 if b == 0:\n\u00a0 \u00a0 \u00a0 \u00a0 raise ValueError(\"Only Chuck Norris can divide by 0!\")\n\u00a0 \u00a0 return a \/ b\n\n\ntry:\n\u00a0 \u00a0 result = divide(10, 0)\nexcept ValueError as e:\n\u00a0 \u00a0 print(f\"Error: {e}\")\nexcept TypeError:\n\u00a0 \u00a0 print(\"Do not compare apples and orange!\")<\/code><\/pre>\n<p class=\"wp-block-paragraph\">In this example, a <code>ValueError<\/code> exception is triggered if the divisor is zero. In this way, you can explicitly control the error conditions. In the print function, the message will be \u201c<em>Error: Only Chuck Norris can divide by 0!<\/em>\u201c.<\/p>\n<h3 class=\"wp-block-heading\"><strong>Some of the most common exceptions<\/strong><\/h3>\n<p class=\"wp-block-paragraph\"><strong>ValueError<\/strong>: The type of a value is correct but its value is invalid.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">try:\n\u00a0 \u00a0 number = math.sqrt(-10)\nexcept ValueError:\n\u00a0 print(\"It's too complex to be real!\")<\/code><\/pre>\n<p class=\"wp-block-paragraph\"><strong>KeyError<\/strong>: Trying to access a key that doesn\u2019t exist in a dictionary.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">data = {\"name\": \"Alice\"}\ntry:\n\u00a0 \u00a0 age = data[\"age\"]\nexcept KeyError:\n\u00a0 \u00a0 print(\"Never ask a lady her age!\")<\/code><\/pre>\n<p class=\"wp-block-paragraph\"><strong>IndexError<\/strong>: Trying to access a non-existent index in a list.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">items = [1, 2, 3]\ntry:\n\u00a0 \u00a0 print(items[3])\nexcept IndexError:\n\u00a0 \u00a0 print(\"You forget that indexing starts at 0, don't you?\")<\/code><\/pre>\n<p class=\"wp-block-paragraph\"><strong>TypeError<\/strong>: Performing an operation on incompatible types.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">try:\n\u00a0 \u00a0 result = \"text\" + 5\nexcept TypeError:\n\u00a0 \u00a0 print(\"Do not compare apples and orange!\")<\/code><\/pre>\n<p class=\"wp-block-paragraph\"><strong>FileNotFoundError<\/strong>: Trying to open a non-existing file.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">try:\n\u00a0 \u00a0 with open(\"notexisting_file.txt\", \"r\") as file:\n\u00a0 \u00a0 \u00a0 \u00a0 content = file.read()\nexcept FileNotFoundError:\n\u00a0 \u00a0 print(\"Are you sure of your path?\")<\/code><\/pre>\n<p class=\"wp-block-paragraph\"><strong>Custom Error<\/strong>: You can trigger predefined exceptions or also define your own exception classes:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">class CustomError(Exception):\n\u00a0 \u00a0 pass\n\ntry:\n\u00a0 \u00a0 raise CustomError(\"This is a custom error\")\nexcept CustomError as e:\n\u00a0 \u00a0 print(f\"Catched error: {e}\")<\/code><\/pre>\n<h3 class=\"wp-block-heading\">\n<strong>Clean with the <\/strong><strong><em>finally <\/em><\/strong><strong>statement<\/strong><br \/>\n<\/h3>\n<p class=\"wp-block-paragraph\">The <code>finally<\/code> block is executed in every case, regardless of whether the error has occurred or not. It is often used to perform cleanup actions, such as closing a connection to a database or releasing resources.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import sqlite3\n\ntry:\n\u00a0 \u00a0 conn = sqlite3.connect(\"users_db.db\")\u00a0 # Connect to a database\n\u00a0 \u00a0 cursor = conn.cursor()\n\u00a0 \u00a0 cursor.execute(\"SELECT * FROM users\")\u00a0 # Execute a query\n\u00a0 \u00a0 results = cursor.fetchall()\u00a0 # Get result of the query\n\u00a0 \u00a0 print(results)\nexcept sqlite3.DatabaseError as e:\n\u00a0 \u00a0 print(\"Database error:\", e)\nfinally:\n\u00a0 \u00a0 print(\"Closing the database connection.\")\n\u00a0 \u00a0 if 'conn' in locals():\n\u00a0 \u00a0 \u00a0 \u00a0 conn.close()\u00a0 # Ensures the connection is closed<\/code><\/pre>\n<h3 class=\"wp-block-heading\"><strong>Best practices for error handling<\/strong><\/h3>\n<ol class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\n<strong>Catch specific exceptions<\/strong>: Avoid using a generic except block without specifying an exception, as it may mask unexpected errors. Prefer specifying the exception:<\/li>\n<\/ol>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\"># Bad practice\ntry:\n\u00a0 \u00a0 result = 10 \/ 0\nexcept Exception as e:\n\u00a0 \u00a0 print(f\"Error: {e}\")\n\n# Good practice\ntry:\n\u00a0 \u00a0 result = 10 \/ 0\nexcept ZeroDivisionError as e:\u00a0\n\u00a0 \u00a0 print(f\"Error: {e}\")<\/code><\/pre>\n<ol start=\"2\" class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\n<strong>Provide explicit messages<\/strong>: Add clear and descriptive messages when raising or handling exceptions.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>Avoid silent failures<\/strong>: If you catch an exception, ensure it is logged or re-raised so it doesn\u2019t go unnoticed.<\/li>\n<\/ol>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import logging\n\nlogging.basicConfig(level=logging.ERROR)\n\ntry:\n\u00a0 \u00a0 result = 10 \/ 0\nexcept ZeroDivisionError:\n\u00a0 \u00a0 logging.error(\"Division by zero detected.\")<\/code><\/pre>\n<ol start=\"4\" class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\n<strong>Use <\/strong><code>else<\/code><strong> and <\/strong><code>finally<\/code><strong> blocks<\/strong>: The <code>else<\/code> block runs only if no exception is raised in the <code>try<\/code> block.<\/li>\n<\/ol>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">try:\n\u00a0 \u00a0 result = 10 \/ 2\nexcept ZeroDivisionError:\n\u00a0 \u00a0 logging.error(\"Division by zero detected.\")\nelse:\n\u00a0 \u00a0 logging.info(f\"Success: {result}\")\nfinally:\n\u00a0 \u00a0 logging.info(\"End of processing.\")<\/code><\/pre>\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-dotted\">\n<h2 class=\"wp-block-heading\"><strong>II \u2013 How to handle Python logs?<\/strong><\/h2>\n<p class=\"wp-block-paragraph\">Good error-handling is one thing, but if no one knows that an error has occurred, the whole point is lost. As explained in the introduction, the monitor is rarely consulted or even seen when a program is running in production. No one will see print. Therefore, good error handling must be accompanied by a good logging system.<\/p>\n<h3 class=\"wp-block-heading\"><strong>What are logs?<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">Logs are records of messages generated by a program to track the events that occur during its execution. These messages may contain information about errors, warnings, successful actions, process milestones or other relevant events. Logs are essential for debugging, tracking performance and monitoring the health of an application. They allow developers to understand what is going on in a program without having to interrupt its execution, making it easier to solve problems and continuously improve the software.<\/p>\n<h3 class=\"wp-block-heading\"><strong>The loguru package<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">Python already has a native logging package: logging. But we prefer the loguru package, which is much simpler to use and easier to configure. In fact, complete output formatting is already preconfigured.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">from loguru import logger\nlogger.debug(\"A pretty debug message!\")<\/code><\/pre>\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" height=\"64\" width=\"1024\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/03\/Capture-decran-2025-03-25-202636-1024x64.png?resize=1024%2C64&#038;ssl=1\" alt=\"\" class=\"wp-image-600333\"><figcaption class=\"wp-element-caption\">Image from author.<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">All the important elements are included directly in the message:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">Time stamp<\/li>\n<li class=\"wp-block-list-item\">Log level, indicating the seriousness of the message.<\/li>\n<li class=\"wp-block-list-item\">File location, module and line number. In this example, the file location is __main__ because it was executed directly from the command line. The module is &lt;module&gt; due to the fact that the log is not located in a class or function.<\/li>\n<li class=\"wp-block-list-item\">The message.<\/li>\n<\/ul>\n<h3 class=\"wp-block-heading\"><strong>The different logging levels<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">There are several log levels to take into account the importance of the message displayed (which is more complicated in a print). Each level has a name and an associated number:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\n<strong>TRACE <\/strong>(5): used to record detailed information on the program\u2019s execution path for diagnostic purposes.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>DEBUG <\/strong>(10): used by developers to record messages for debugging purposes.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>INFO <\/strong>(20): used to record information messages describing normal program operation.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>SUCCESS <\/strong>(25): similar to INFO, but used to indicate the success of an operation.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>WARNING <\/strong>(30): used to indicate an unusual event that may require further investigation.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>ERROR <\/strong>(40): used to record error conditions that have affected a specific operation.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>CRITICAL <\/strong>(50): used to record error conditions that prevent a main function from working.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">The package naturally handles different formatting depending on the level used<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">from loguru import logger\n\nlogger.trace(\"A trace message.\")\nlogger.debug(\"A debug message.\")\nlogger.info(\"An information message.\")\nlogger.success(\"A success message.\")\nlogger.warning(\"A warning message.\")\nlogger.error(\"An error message.\")\nlogger.critical(\"A critical message.\")<\/code><\/pre>\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" height=\"195\" width=\"1024\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/03\/Capture-decran-2025-03-25-202755-1024x195.png?resize=1024%2C195&#038;ssl=1\" alt=\"\" class=\"wp-image-600334\"><figcaption class=\"wp-element-caption\">Image from author.<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">The trace message was not displayed because the default minimum level used by loguru is debug. It therefore ignores all messages at lower levels.<\/p>\n<p class=\"wp-block-paragraph\">It is possible to define new log levels with the level method and is used with the log method<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">logger.level(\"FATAL\", no=60, color=\"&lt;red&gt;\", icon=\"!!!\")\nlogger.log(\"FATAL\", \"A FATAL event has just occurred.\")<\/code><\/pre>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">name : the name of the log level.<\/li>\n<li class=\"wp-block-list-item\">no : the corresponding severity value (must be an integer).<\/li>\n<li class=\"wp-block-list-item\">color : color markup.<\/li>\n<li class=\"wp-block-list-item\">icon : the level icon.<\/li>\n<\/ul>\n<h3 class=\"wp-block-heading\"><strong>The logger configuration<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">It is possible to recreate a logger with a new configuration by deleting the old one with the <code>remove<\/code> command and generating a new logger with a new configuration with the <code>add<\/code> function. This function takes the following arguments:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\n<strong>sink [mandatory]<\/strong>: specifies a target for each data set created by the logger. By default, this value is set to <code>sys.stderr<\/code> (which corresponds to the standard error output).\u00a0 We can also store all output in a \u201c.log\u201d file (except if you have a log collector).<\/li>\n<li class=\"wp-block-list-item\">\n<strong>level<\/strong>: Sets the minimum logging level for the recorder.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>format<\/strong>: is useful to define a custom format for your logs. To maintain the coloring of the logs in the terminal, this must be specified (see example below).<\/li>\n<li class=\"wp-block-list-item\">\n<strong>filter<\/strong>: is used to determine whether a log should be recorded or not.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>colorize<\/strong>: takes a boolean value and determines whether the terminal coloring should be activated or not.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>serialize<\/strong>: causes the log to be displayed in JSON format if it is set to <code>True<\/code>.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>backtrace<\/strong>: determines whether the exception trace should go beyond the point at which the error was recorded in order to facilitate troubleshooting.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>diagnose<\/strong>: Determines whether variable values should be displayed in the exception trace. This option must be set to <code>False<\/code> in production environments so that no sensitive information is leaked.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>enqueue<\/strong>: If this option is activated, the log data records are placed in a queue to avoid conflicts if several processes connect to the same target.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>catch<\/strong>: If an unexpected error occurs when connecting to the server specified sink, you can detect it by setting this option to <code>True<\/code>. The error will be displayed in the standard error.<\/li>\n<\/ul>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import sys\nfrom loguru import logger\n\nlogger_format = (\n    \"{time:YYYY-MM-DD HH:mm:ss.SSS} | \"\n    \"{level: &lt;8} | \"\n    \"{name}:{function}:{line}\"\n)\nlogger.remove()\nlogger.add(sys.stderr, format=logger_format)\n    <\/code><\/pre>\n<p class=\"has-surface-secondary-background-color has-background has-underline-1-font-size wp-block-paragraph\"><strong>Note<\/strong>:<br \/>Colors disappear in a file. This is because there are special characters (called <strong>ansi <\/strong>codes) that display colors in the terminal, but this formatting does not exist in the files.<\/p>\n<p class=\"wp-block-paragraph\"><strong>Add context to logs<\/strong><\/p>\n<p class=\"wp-block-paragraph\">For complex applications, it can be useful to add further information to the logs to enable sorting and facilitate troubleshooting.<\/p>\n<p class=\"wp-block-paragraph\">For example, if a user changes a database, it can be useful to have the user ID in addition to the change information.<\/p>\n<p class=\"wp-block-paragraph\">Before you start recording context data, you need to make sure that the <code>{extra}<\/code> directive is included in your custom format. This variable is a Python dictionary that contains context data for each log entry (if applicable).<\/p>\n<p class=\"wp-block-paragraph\">Here is an example of a customization where an extra <code>user_id<\/code> is added. In this format, the colors.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import sys\nfrom loguru import logger\n\n\nlogger_format = (\n\u00a0 \u00a0 \"&lt;green&gt;{time:YYYY-MM-DD HH:mm:ss.SSS}&lt;\/green&gt; | \"\n\u00a0 \u00a0 \"&lt;level&gt;{level: &lt;8}&lt;\/level&gt; | \"\n\u00a0 \u00a0 \"&lt;cyan&gt;{name}&lt;\/cyan&gt;:&lt;cyan&gt;{function}&lt;\/cyan&gt;:&lt;cyan&gt;{line}&lt;\/cyan&gt; | \"\n\u00a0 \u00a0 \"User ID: {extra[user_id]} - &lt;level&gt;{message}&lt;\/level&gt;\"\n)\nlogger.configure(extra={\"user_id\": \"\"})\u00a0 # Default value\nlogger.remove()\nlogger.add(sys.stderr, format=logger_format)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">It is now possible to use the bind method to create a child logger inheriting all the data from the parent logger.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">childLogger = logger.bind(user_id=\"001\")\nchildLogger.info(\"Here a message from the child logger\")\n\nlogger.info(\"Here a message from the parent logger\")<\/code><\/pre>\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" height=\"119\" width=\"1024\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/03\/Capture-decran-2025-03-25-203019-1024x119.png?resize=1024%2C119&#038;ssl=1\" alt=\"\" class=\"wp-image-600335\"><figcaption class=\"wp-element-caption\">Image from author.<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Another way to do this is to use the contextualize method in a with block.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">with logger.contextualize(user_id=\"001\"):\n\u00a0 \u00a0 logger.info(\"Here a message from the logger with user_id 001\")\n\nlogger.info(\"Here a message from the logger without user_id\")<\/code><\/pre>\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" height=\"121\" width=\"1024\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/03\/Capture-decran-2025-03-25-203148-1024x121.png?resize=1024%2C121&#038;ssl=1\" alt=\"\" class=\"wp-image-600336\"><figcaption class=\"wp-element-caption\">Image from author.<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Instead of the with block, you can use a <strong>decorator<\/strong>. The preceding code then becomes<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">@logger.contextualize(user_id=\"001\")\ndef child_logger():\n\u00a0 \u00a0 logger.info(\"Here a message from the logger with user_id 001\")\n\nchild_logger()\n\nlogger.info(\"Here a message from the logger without user_id\")<\/code><\/pre>\n<h3 class=\"wp-block-heading\"><strong>The catch method<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">Errors can be automatically logged when they occur using the catch method.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">def test(x):\n\u00a0 \u00a0 50\/x\n\nwith logger.catch():\n\u00a0 \u00a0 test(0)<\/code><\/pre>\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/03\/AD_4nXfxonh-FKQnP5IpaVrhR8J0vb1wYsUwK71csqSqEr2-8ThmtHdgWSWqtcpKXrqgIOwLLB3pBPGbDUUb3Tl7J9MwVbOuvakLeA7Y7lC-jB2wKe4RyIWfBTO7gU-yw_wRBiJjHWcdnw.png?ssl=1\" alt=\"\" class=\"wp-image-600649\"><figcaption class=\"wp-element-caption\">Image from author.<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">But it\u2019s simpler to use this method as a decorator. This results in the following code<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">@logger.catch()\ndef test(x):\n\u00a0 \u00a0 50\/x\n\ntest(0)<\/code><\/pre>\n<h3 class=\"wp-block-heading\"><strong>The log file<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">A production application is designed to run continuously and uninterrupted. In some cases, it is important to predict the behavior of the file, otherwise you will have to consult pages of logs in the event of an error.<\/p>\n<p class=\"wp-block-paragraph\">Here are the different conditions under which a file can be modified:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\n<strong>rotation<\/strong>: specifies a condition under which the current log file is closed and a new file is created. This condition can be an int, a datetime or a str. Str is recommended as it is easier to read.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>retention<\/strong>: specifies how long each log file should be kept before it is deleted from the file system.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>compression<\/strong>: The log file is converted to the specified compression format if this option is activated.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>delay<\/strong>: If this option is set to True, the creation of a new log file is delayed until the first log message has been pushed.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>mode<\/strong>, <strong>buffering<\/strong>, <strong>encoding <\/strong>: Parameters that are passed to the Python function open and determine how Python opens log files.\u00a0<\/li>\n<\/ul>\n<p class=\"has-surface-tertiary-background-color has-background has-underline-1-font-size wp-block-paragraph\" style=\"border-radius:0px\"><strong>Note<\/strong>:<br \/>Usually, in the case of a production application, a log collector will be set up to retrieve the app\u2019s outputs directly. <strong>It is therefore not necessary to create a log file.<\/strong><\/p>\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-dotted\">\n<h2 class=\"wp-block-heading\"><strong>Conclusion<\/strong><\/h2>\n<p class=\"wp-block-paragraph\">Error handling in Python is an important step in writing professional and reliable code. By combining try-except blocks, the raise statement, and the finally block, you can handle errors predictably while maintaining readable and maintainable code.<\/p>\n<p class=\"wp-block-paragraph\">Moreover, a good logging system improves the ability to monitor and debug your application. Loguru provides a simple and flexible package for logging messages and can therefore be easily integrated into your codebase.<\/p>\n<p class=\"wp-block-paragraph\">In summary, combining effective error handling with a comprehensive logging system can significantly improve the reliability, maintainability, and debugging capability of your Python applications.<\/p>\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-dotted\">\n<h2 class=\"wp-block-heading\"><strong>References<\/strong><\/h2>\n<p class=\"wp-block-paragraph\">1 \u2013 Error handling in Python: <a href=\"https:\/\/docs.python.org\/3\/tutorial\/errors.html\">official Python documentation on exceptions<\/a><\/p>\n<p class=\"wp-block-paragraph\">2 \u2013 The loguru documentation: <a href=\"https:\/\/loguru.readthedocs.io\/en\/stable\/\">https:\/\/loguru.readthedocs.io\/en\/stable\/<\/a><\/p>\n<p class=\"wp-block-paragraph\">3 \u2013 Guide about loguru: <a href=\"https:\/\/betterstack.com\/community\/guides\/logging\/loguru\/\">https:\/\/betterstack.com\/community\/guides\/logging\/loguru\/<\/a><\/p>\n<p>The post <a href=\"https:\/\/towardsdatascience.com\/data-science-from-school-to-work-part-iii\/\">Data Science: From School to Work, Part III<\/a> appeared first on <a href=\"https:\/\/towardsdatascience.com\/\">Towards Data Science<\/a>.<\/p>\n<\/div>\n<p> \t<BR><br \/>\n <BR><\/BR><br \/>\n    Vincent Margot<br \/>\n \t<BR><br \/>\n<BR><\/BR><br \/>\n<a href=\"https:\/\/towardsdatascience.com\/data-science-from-school-to-work-part-iii\/\">Go to original source<\/a><br \/>\n \t<BR><br \/>\n <BR><\/BR><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Data Science: From School to Work, Part III Introduction Writing code is about solving problems, but not every problem is predictable. In the real world, your software will encounter unexpected situations: missing files, invalid user inputs, network timeouts, or even hardware failures. This is why handling errors isn\u2019t just a nice-to-have; it\u2019s a critical part [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[62,83,2165,160,157,2166,158],"tags":[368,2168,2167],"class_list":["post-2697","post","type-post","status-publish","format-standard","hentry","category-aimldsaimlds","category-data-science","category-error-handling","category-programming","category-python","category-python-logging","category-tips-and-tricks","tag-code","tag-error","tag-handling"],"_links":{"self":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts\/2697"}],"collection":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/comments?post=2697"}],"version-history":[{"count":0,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts\/2697\/revisions"}],"wp:attachment":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/media?parent=2697"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/categories?post=2697"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/tags?post=2697"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}