Good python coding examples for the software development | PyShine

Good python coding examples for the software development

 · 48 mins read

Hello friends! Below are some examples that you can use to write better codes.

1. Use meaningful variable names:


# Good
name = "John Doe"

# Bad
n = "John Doe"

2. Write descriptive docstrings for functions and modules:


def greet(name):
    """This function greets the person passed in as a parameter"""
    print("Hello, " + name + ". How are you today?")

3. Use try-except blocks to handle exceptions:

try:
    # some code here
except Exception as e:
    # handle exception here

4. Use the ‘with’ statement when working with files:

with open("file.txt", "r") as file:
    data = file.read()
    # do something with the file data

5. Avoid using a single leading underscore (_) to indicate a weak “internal use” variable. Use double leading underscores to avoid naming collisions in subclasses.

# Good
class MyClass:
    def __init__(self):
        self.__variable = 42

# Bad
class MyClass:
    def __init__(self):
        self._variable = 42

6. Use list comprehensions instead of map and filter when possible:

# Good
squared_numbers = [x**2 for x in numbers]

# Bad
squared_numbers = map(lambda x: x**2, numbers)

7. Use the built-in Python functions and libraries before writing your own implementation:

# Good
import os
os.remove("file.txt")

# Bad
import shutil
shutil.rmtree("file.txt")

8. Use PEP 8 style guide for writing code:

# Good
def greet_person(person_name):
    print("Hello, " + person_name + "!")

# Bad
def greetPerson(personName):
    print("Hello, " + personName + "!")

9. Use is and is not instead of equality (==) and inequality (!=) when comparing objects to None:

# Good
if value is None:
    # do something

# Bad
if value == None:
    # do something

10. Use context managers (with statement) when working with resources like files, sockets, and databases to ensure that they are properly cleaned up when done:

# Good
with open("file.txt", "w") as file:
    file.write("Hello, World!")

# Bad
file = open("file.txt", "w")
file.write("Hello, World!")
file.close()

11. Use Python’s built-in logging module instead of print statements for logging and debugging:

# Good
import logging

logging.basicConfig(level=logging.DEBUG)
logging.debug("Debug message")

# Bad
print("Debug message")

12. Use functions to extract complex logic and make code reusable:

# Good
def calculate_sum(a, b):
    return a + b

result = calculate_sum(2, 3)

# Bad
result = 2 + 3

13. Use the with statement when working with databases to ensure that database connections are properly closed:

# Good
import sqlite3

with sqlite3.connect("database.db") as conn:
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM users")
    rows = cursor.fetchall()

# Bad
import sqlite3

conn = sqlite3.connect("database.db")
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
conn.close()

14. Use list comprehensions instead of for loops for simple data manipulations:

# Good
squared_numbers = [x**2 for x in range(1, 10)]

# Bad
squared_numbers = []
for x in range(1, 10):
    squared_numbers.append(x**2)

15. Use the if name == “main” statement when writing script files:

def main():
    # Main code here

if __name__ == "__main__":
    main()

This ensures that the code in the script file is only executed when the file is run as the main program, and not when it is imported as a module.

16. Use the with statement when working with locks to ensure that the lock is properly released:

import threading

lock = threading.Lock()

# Good
with lock:
    # Critical section

# Bad
lock.acquire()
try:
    # Critical section
finally:
    lock.release()

17. Use Python’s built-in unittest module for writing and running tests:


import unittest

class TestSum(unittest.TestCase):
    def test_sum(self):
        self.assertEqual(sum([1, 2, 3]), 6, "Should be 6")

if __name__ == '__main__':
    unittest.main()

18. Use the enum module to define named constants:

import enum

class Color(enum.Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

# Good
if color == Color.RED:
    # do something

# Bad
if color == 1:
    # do something

19. Use the collections module for working with data structures such as defaultdict, Counter, and namedtuple:

from collections import defaultdict

# Good
word_count = defaultdict(int)
for word in words:
    word_count[word] += 1

# Bad
word_count = {}
for word in words:
    if word in word_count:
        word_count[word] += 1
    else:
        word_count[word] = 1

20. Use the itertools module for working with iterators and generators:

import itertools

# Good
squared_numbers = list(map(lambda x: x**2, range(1, 10)))

# Bad
squared_numbers = []
for x in range(1, 10):
    squared_numbers.append(x**2)


21. Use try-except blocks to handle exceptions:

# Good
try:
    # code that may raise an exception
except Exception as e:
    # handle the exception

# Bad
try:
    # code that may raise an exception
except:
    # handle the exception

22. Use the with statement to automatically close files:

# Good
with open("file.txt", "r") as f:
    # read from file

# Bad
f = open("file.txt", "r")
try:
    # read from file
finally:
    f.close()

23. Use the os module to interact with the operating system:

import os

# Good
if os.path.exists("file.txt"):
    # do something

# Bad
import os.path
if os.path.exists("file.txt"):
    # do something

24. Use the shutil module to manipulate files and directories:

import shutil

# Good
shutil.copyfile("src.txt", "dst.txt")

# Bad
import os
os.system("cp src.txt dst.txt")

25. Use the re module to work with regular expressions:

import re

# Good
match = re.search(r"\d+", "Number: 42")

# Bad
import string
match = string.find("Number: 42", "42")

26. Use the datetime module to work with dates and times:

import datetime

# Good
now = datetime.datetime.now()

# Bad
import time
now = time.localtime()

27. Use the math module to perform mathematical operations:

import math

# Good
result = math.sqrt(16)

# Bad
result = 16**0.5

28. Use the random module to generate random numbers:

import random

# Good
random_number = random.randint(1, 100)

# Bad
import time
random_number = int(time.time() % 100)

29. Use str.format() method for string formatting:

# Good
name = "John"
print("Hello, {}!".format(name))

# Bad
name = "John"
print("Hello, " + name + "!")

30. Use list comprehensions instead of loops for simple operations:

# Good
numbers = [1, 2, 3, 4, 5]
squared_numbers = [n**2 for n in numbers]

# Bad
numbers = [1, 2, 3, 4, 5]
squared_numbers = []
for n in numbers:
    squared_numbers.append(n**2)

31. Use generators instead of lists when working with large data sets:

# Good
def squares(n):
    for i in range(n):
        yield i**2

# Bad
def squares(n):
    squares = []
    for i in range(n):
        squares.append(i**2)
    return squares

32. Use the enum module to define named constants:

import enum

# Good
class Color(enum.Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

# Bad
RED = 1
GREEN = 2
BLUE = 3

33. Use the collections module for working with collections:

import collections

# Good
counter = collections.Counter("hello world")

# Bad
counter = {}
for c in "hello world":
    if c in counter:
        counter[c] += 1
    else:
        counter[c] = 1

34. Use the functools module for working with functions:

Use the functools module for working with functions:

35. Use the itertools module for working with iterators:

import itertools

# Good
even_numbers = itertools.islice(itertools.count(0, 2), 5)

# Bad
even_numbers = []
for i in range(0, 10, 2):
    even_numbers.append(i)

36. Use the logging module for logging messages:

import logging

# Good
logging.basicConfig(level=logging.INFO)
logging.debug("Debug message")
logging.info("Info message")

# Bad
if debug:
    print("Debug message")
print("Info message")

37. Use with statement when working with files or other resources:

# Good
with open("file.txt", "r") as f:
    content = f.read()

# Bad
f = open("file.txt", "r")
content = f.read()
f.close()

38. Use the unittest module for writing unit tests:

import unittest

# Good
class TestStringMethods(unittest.TestCase):
    def test_upper(self):
        self.assertEqual("foo".upper(), "FOO")

# Bad
def test_upper():
    assert "foo".upper() == "FOO"

39. Use assert statements to check for preconditions and postconditions:

# Good
def divide(a, b):
    assert b != 0, "division by zero"
    return a / b

# Bad
def divide(a, b):
    if b == 0:
        raise Exception("division by zero")
    return a / b

40. Use the os and shutil modules for working with files and directories:

import os
import shutil

# Good
if not os.path.exists("directory"):
    os.makedirs("directory")
shutil.copy("file1.txt", "directory")

# Bad
if not os.path.exists("directory"):
    os.system("mkdir directory")
os.system("cp file1.txt directory")

41. Use the contextlib module for creating context managers:

import contextlib

# Good
@contextlib.contextmanager
def make_temp_directory():
    temp_directory = tempfile.mkdtemp()
    try:
        yield temp_directory
    finally:
        shutil.rmtree(temp_directory)

# Bad
temp_directory = tempfile.mkdtemp()
try:
    # do something with temp_directory
finally:
    shutil.rmtree(temp_directory)

42. Use the argparse module for parsing command line arguments:

import argparse

# Good
parser = argparse.ArgumentParser()
parser.add_argument("-n", "--name", help="name of the person")
parser.add_argument("-a", "--age", help="age of the person", type=int)
args = parser.parse_args()

# Bad
import sys

if len(sys.argv) < 3:
    print("usage: script.py -n name -a age")
    sys.exit(1)
if sys.argv[1] == "-n":
    name = sys.argv[2]

43. Use the collections module for working with data structures:

import collections

# Good
counter = collections.Counter([1, 2, 2, 3, 3, 3])
print(counter)

# Bad
counter = {}
for item in [1, 2, 2, 3, 3, 3]:
    if item in counter:
        counter[item] += 1
    else:
        counter[item] = 1
print(counter)

44. Use the re module for working with regular expressions:

import re

# Good
result = re.search("\d{3}-\d{2}-\d{4}", "Social Security Number: 123-45-6789")
print(result.group(0))

# Bad
string = "Social Security Number: 123-45-6789"
start = string.find("123")
end = start + len("123-45-6789")
print(string[start:end])

45. Use the datetime module for working with dates and times:

import datetime

# Good
today = datetime.datetime.now().date()
print(today)

# Bad
from time import gmtime, strftime
print(strftime("%Y-%m-%d", gmtime()))

46. Use the bisect module for working with sorted lists:

import bisect

# Good
arr = [1, 2, 3, 4, 4, 4, 5]
index = bisect.bisect_left(arr, 4)
print(index)

# Bad
arr = [1, 2, 3, 4, 4, 4, 5]
index = 0
for i, item in enumerate(arr):
    if item >= 4:
        index = i
        break
print(index)

47. Use the itertools module for working with iterators:

import itertools

# Good
numbers = [1, 2, 3, 4, 5]
result = list(itertools.combinations(numbers, 2))
print(result)

# Bad
numbers = [1, 2, 3, 4, 5]
result = []
for i in range(len(numbers)):
    for j in range(i + 1, len(numbers)):
        result.append((numbers[i], numbers[j]))
print(result)

48. Use the functools module for working with functions:

import functools

# Good
def add(a, b):
    return a + b
add = functools.partial(add, b=10)
print(add(5))

# Bad
def add(a, b=10):
    return a + b
print(add(5))

49. Use the threading module for working with threads:

import threading

# Good
def worker():
    print("worker")

thread = threading.Thread(target=worker)
thread.start()
thread.join()

50. Use the os module for working with the operating system:

import os

# Good
print(os.path.join("data", "input.txt"))

# Bad
print("data" + os.sep + "input.txt")

51. Use the shutil module for working with file objects:

import shutil

# Good
shutil.copy2("input.txt", "input_backup.txt")

# Bad
with open("input.txt", "r") as src:
    with open("input_backup.txt", "w") as dst:
        dst.write(src.read())

52. Use the glob module for working with file patterns:

import glob

# Good
files = glob.glob("*.txt")
print(files)

# Bad
import os
files = [file for file in os.listdir() if file.endswith(".txt")]
print(files)

53. Use the pickle module for working with binary data:

import pickle

# Good
data = {"name": "John Doe", "age": 30}
with open("data.pkl", "wb") as file:
    pickle.dump(data, file)

# Bad
data = {"name": "John Doe", "age": 30}
with open("data.txt", "w") as file:
    file.write(str(data))

54. Use the csv module for working with CSV files:

import csv

# Good
data = [["name", "age"], ["John Doe", 30]]
with open("data.csv", "w", newline="") as file:
    writer = csv.writer(file)
    writer.writerows(data)

# Bad
data = [["name", "age"], ["John Doe", 30]]
with open("data.csv", "w") as file:
    for row in data:
        file.write(",".join(row) + "\n")

55. Use the json module for working with JSON data:

import json

# Good
data = {"name": "John Doe", "age": 30}
with open("data.json", "w") as file:
    json.dump(data, file)

# Bad
data = {"name": "John Doe", "age": 30}
with open("data.json", "w") as file:
    file.write(str(data))

56. Use try…except blocks to handle exceptions:

# Good
try:
    result = 1 / 0
except ZeroDivisionError:
    print("Cannot divide by zero")

# Bad
result = 1 / 0
print("This line will never be reached")

57. Use with statements to work with context managers:

# Good
with open("data.txt", "r") as file:
    data = file.read()

# Bad
file = open("data.txt", "r")
data = file.read()
file.close()

58. Use assert statements for debugging and testing:

# Good
assert len(data) > 0, "Data is empty"

# Bad
if len(data) == 0:
    raise ValueError("Data is empty")

59. Use is and is not instead of == and != when comparing to None:

# Good
if data is None:
    print("Data is None")

# Bad
if data == None:
    print("Data is None")

60. Use else blocks in for and while loops to specify an else block that is executed if the loop terminates normally (i.e., without encountering a break statement):

# Good
for number in range(10):
    if number == 5:
        break
else:
    print("5 not found")

# Bad
found = False
for number in range(10):
    if number == 5:
        found = True
        break
if not found:
    print("5 not found")

61. Use enumerate() function to loop over a list and get both the index and the value:

# Good
fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
    print(index, fruit)

# Bad
fruits = ["apple", "banana", "cherry"]
for i in range(len(fruits)):
    print(i, fruits[i])

62. Use list comprehensions instead of loops for simple operations on lists:

# Good
squared_numbers = [x ** 2 for x in range(10)]

# Bad
squared_numbers = []
for x in range(10):
    squared_numbers.append(x ** 2)

63. Use zip() function to loop over multiple lists in parallel:

# Good
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
for name, age in zip(names, ages):
    print(name, age)

# Bad
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
for i in range(len(names)):
    print(names[i], ages[i])

64. Use dict.get() method instead of dict[key] to avoid KeyError:

# Good
person = {"name": "Alice", "age": 25}
age = person.get("age", 0)

# Bad
person = {"name": "Alice", "age": 25}
age = person["age"]

65. Use defaultdict from the collections module instead of dict when you need a dictionary with default values:

# Good
from collections import defaultdict

person = defaultdict(str)
person["name"] = "Alice"
print(person["age"])  # Output: ''

# Bad
person = {}
person["name"] = "Alice"
try:
    print(person["age"])
except KeyError:
    print("Age not found")

66. Use map() and filter() functions to apply operations to lists:

# Good
numbers = [1, 2, 3, 4, 5]
squared_numbers = list(map(lambda x: x ** 2, numbers))
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))

# Bad
numbers = [1, 2, 3, 4, 5]
squared_numbers = []
for number in numbers:
    squared_numbers.append(number ** 2)
even_numbers = []
for number in numbers:
    if number % 2 == 0:
        even_numbers.append(number)

67. Use functools.partial() to partially apply functions:

# Good
from functools import partial

def multiply(a, b):
    return a * b

double = partial(multiply, 2)
print(double(3))  # Output: 6

# Bad
def double(b):
    return 2 * b

68. Use itertools functions to work with iterators:

# Good
import itertools

numbers = [1, 2, 3, 4, 5]
combinations = list(itertools.combinations(numbers, 2))

# Bad
numbers = [1, 2, 3, 4, 5]
combinations = []
for i in range(len(numbers)):
    for j in range(i + 1, len(numbers)):
        combinations.append((numbers[i], numbers[j]))

69. Use namedtuple from the collections module instead of tuples:

# Good
from collections import namedtuple

Person = namedtuple("Person", ["name", "age"])
person = Person("Alice", 25)

# Bad
person = ("Alice", 25)

70. Use dataclasses module for defining classes with default implementations for special methods:

# Good
from dataclasses import dataclass

@dataclass
class Person:
    name: str
    age: int

person = Person("Alice", 25)

# Bad
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

person = Person("Alice", 25)

71. Use the format method for string formatting:

# Good
name = "Alice"
age = 25
print("My name is {0} and I am {1} years old.".format(name, age))

# Bad
name = "Alice"
age = 25
print("My name is " + name + " and I am " + str(age) + " years old.")

72. Use enumerate to iterate over lists and keep track of the index:

# Good
names = ["Alice", "Bob", "Charlie"]
for i, name in enumerate(names):
    print(i, name)

# Bad
names = ["Alice", "Bob", "Charlie"]
for i in range(len(names)):
    print(i, names[i])

73. Use list comprehensions for simple list transformations:

# Good
numbers = [1, 2, 3, 4, 5]
squared_numbers = [number ** 2 for number in numbers]

# Bad
numbers = [1, 2, 3, 4, 5]
squared_numbers = []
for number in numbers:
    squared_numbers.append(number ** 2)

74. Use the with statement when working with resources that need to be cleaned up, such as files:

# Good
with open("file.txt", "r") as f:
    contents = f.read()

# Bad
f = open("file.txt", "r")
contents = f.read()
f.close()

75. Use zip to iterate over multiple lists in parallel:

# Good
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
for name, age in zip(names, ages):
    print(name, age)

# Bad
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
for i in range(len(names)):
    print(names[i], ages[i])

76. Use exceptions to handle errors instead of returning error codes:

# Good
try:
    result = divide(a, b)
except ZeroDivisionError:
    print("Cannot divide by zero.")

# Bad
result = divide(a, b)
if result == ERROR_CODE:
    print("Cannot divide by zero.")

77. Use the else clause in a for loop to perform an action when the loop finishes without being interrupted:

# Good
numbers = [1, 2, 3, 4, 5]
for number in numbers:
    if number == 3:
        break
else:
    print("Loop finished without being interrupted.")

# Bad
numbers = [1, 2, 3, 4, 5]
interrupted = False
for number in numbers:
    if number == 3:
        interrupted = True
        break
if not interrupted:
    print("Loop finished without being interrupted.")

78. Use the repr method to provide a string representation of an object that can be used to recreate it:

# Good
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return "Point({0}, {1})".format(self.x, self.y)

# Bad
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return "({0}, {1})".format(self.x, self.y)

79. Use the with statement when working with resources that need to be cleaned up, such as databases:

# Good
with conn:
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM users")
    users = cursor.fetchall()

# Bad
conn = connect()
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")
users = cursor.fetchall()
conn.close()

80. Use the else clause in a while loop to perform an action when the loop finishes without being interrupted:

# Good
i = 0
while i < 5:
    if i == 3:
        break
    i += 1
else:
    print("Loop finished without being interrupted.")

# Bad
i = 0
interrupted = False
while i < 5:
    if i == 3:
        interrupted = True
        break
    i += 1
if not interrupted:
    print("Loop finished without being interrupted.")

81. Use the enumerate function when iterating over a sequence to keep track of the index:

# Good
words = ["apple", "banana", "cherry"]
for i, word in enumerate(words):
    print(i, word)

# Bad
words = ["apple", "banana", "cherry"]
i = 0
for word in words:
    print(i, word)
    i += 1

82. Use the zip function when iterating over multiple sequences in parallel:

# Good
words = ["apple", "banana", "cherry"]
lengths = [5, 6, 6]
for word, length in zip(words, lengths):
    print(word, length)

# Bad
words = ["apple", "banana", "cherry"]
lengths = [5, 6, 6]
for i in range(len(words)):
    print(words[i], lengths[i])

83. Use list comprehensions instead of filter and map when possible:

# Good
squared = [x ** 2 for x in range(10) if x % 2 == 0]

# Bad
squared = list(map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, range(10))))

84. Use the None object instead of False or other values to represent a lack of value:

# Good
def divide(a, b):
    if b == 0:
        return None
    return a / b

# Bad
def divide(a, b):
    if b == 0:
        return False
    return a / b

85. Use the assert statement to check for conditions that should always be true:

# Good
assert divide(4, 2) == 2

# Bad
result = divide(4, 2)
if result != 2:
    raise Exception("Unexpected result.")

86. Use the collections module to work with data structures such as Counter, defaultdict, and OrderedDict:

# Good
from collections import Counter

word = "mississippi"
counter = Counter(word)

# Bad
word = "mississippi"
counter = {}
for letter in word:
    if letter in counter:
        counter[letter] += 1
    else:
        counter[letter] = 1

87. Use the str.format() method instead of string concatenation for string formatting:

# Good
name = "Alice"
print("Hello, {}!".format(name))

# Bad
name = "Alice"
print("Hello, " + name + "!")

88. Use the with statement when working with files or other resources that need to be cleaned up after use:

# Good
with open("file.txt", "r") as file:
    contents = file.read()

# Bad
file = open("file.txt", "r")
contents = file.read()
file.close()

89. Use the try…except statement to handle exceptions:

# Good
try:
    value = int("abc")
except ValueError:
    value = 0

# Bad
value = int("abc")
except ValueError:
    value = 0

90. Use the pass statement as a placeholder when a statement is required syntactically, but no action is needed:

# Good
def noop():
    pass

# Bad
def noop():
    # TODO: implement me!
    return

91. Use the functools module to work with functions, such as partial and reduce:

# Good
from functools import reduce

numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)

# Bad
numbers = [1, 2, 3, 4, 5]
product = 1
for number in numbers:
    product *= number

92. Use the itertools module to work with iterators, such as chain and zip_longest:

# Good
from itertools import chain

words = ["apple", "banana", "cherry"]
letters = chain.from_iterable(words)

# Bad
words = ["apple", "banana", "cherry"]
letters = []
for word in words:
    for letter in word:
        letters.append(letter)

93. Use the enum module to define enumerations:

# Good
from enum import Enum

class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

# Bad
RED = 1
GREEN = 2
BLUE = 3

94. Use the typing module to specify the types of variables, arguments, and return values:

# Good
from typing import List

def reverse(lst: List[int]) -> List[int]:
    return lst[::-1]

# Bad
def reverse(lst):
    return lst[::-1]

95. Use the collections module to work with collections, such as Counter and defaultdict:

# Good
from collections import Counter

words = ["apple", "banana", "cherry", "apple", "banana"]
counter = Counter(words)

# Bad
words = ["apple", "banana", "cherry", "apple", "banana"]
counter = {}
for word in words:
    if word in counter:
        counter[word] += 1
    else:
        counter[word] = 1

96. Use the queue module to work with queues, such as Queue and PriorityQueue:

# Good
from queue import Queue

q = Queue()
q.put("apple")
q.put("banana")
q.put("cherry")

# Bad
q = []
q.append("apple")
q.append("banana")
q.append("cherry")

97. Use the weakref module to work with weak references:

# Good
import weakref

class Node:
    def __init__(self, value):
        self.value = value
        self.next = None

a = Node(1)
b = Node(2)
a.next = weakref.ref(b)

# Bad
class Node:
    def __init__(self, value):
        self.value = value
        self.next = None

a = Node(1)
b = Node(2)
a.next = b

98. Use the copy module to make shallow or deep copies of objects:

# Good
import copy

a = [1, 2, 3]
b = copy.copy(a)
c = copy.deepcopy(a)

# Bad
a = [1, 2, 3]
b = a
c = a[:]

99. Use the dis module to disassemble and inspect Python bytecode:

# Good
import dis

def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

dis.dis(fib)

# Bad
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

print(fib.__code__.co_code)

100. Use the logging module to log messages, such as debug, info, warning, error, and critical:

# Good
import logging

logging.basicConfig(filename="app.log", level=logging.DEBUG)
logging.debug("This is a debug message")
logging.info("This is an info message")
logging.warning("This is a warning message")
logging.error("This is an error message")
logging.critical("This is a critical message")

# Bad
print("[DEBUG] This is a debug message")
print("[INFO] This is an info message")
print("[WARNING] This is a warning message")
print("[ERROR] This is an error message")
print("[CRITICAL] This is a critical message")