Back to Python
2026-04-126 min read

Python 3.7 (EOL)

Learn Python 3.7 (EOL) step by step with clear examples and exercises.

Title: Python 3.7 (End of Life) - A full guide with Examples, Common Pitfalls, and Best Practices

Why This Matters

Python 3.7, though no longer supported as of 2021, remains a valuable learning resource for understanding the fundamentals of Python programming. It serves as a stepping stone for mastering more recent versions like Python 3.8 and beyond. This lesson aims to provide you with an in-depth look at Python 3.7, including its unique features, common mistakes, best practices, and practical applications.

Prerequisites

Before diving into Python 3.7, it's essential to have a foundational understanding of programming concepts such as variables, data types, loops, functions, basic file I/O, and object-oriented programming (OOP) principles. Familiarity with the Python syntax and general programming practices will help you grasp the topics covered in this lesson more effectively.

OOP Concepts

  • Encapsulation
  • Inheritance
  • Polymorphism
  • Abstract classes

Core Concept

Python 3.7 introduced several new features that made it a significant upgrade from its predecessors. Some of these features include:

  1. Async/Await: Python 3.7 introduced async and await keywords for asynchronous programming, which allows concurrent execution of multiple tasks without blocking the event loop.
  2. Fraction and Complex numbers: The built-in Fraction and complex number classes were added to simplify working with rational and complex numbers respectively.
  3. Syntax improvements: Python 3.7 introduced several syntax improvements such as f-strings, type hints, and updated division behavior (3 / 2 now equals 1.5 instead of 1).
  4. Updated standard library: The standard library was updated with new modules like typing, asyncio, and aiohttp.

Async/Await Deep Dive

Async functions are coroutines that can be run concurrently using the event loop. They allow I/O-bound tasks to be performed without blocking the main thread, improving overall performance.

import asyncio

async def print_numbers(n):
for i in range(1, n+1):
await asyncio.sleep(0) # Yield control to the event loop
print(i)

async def main():
tasks = [print_numbers(5) for _ in range(4)]
await asyncio.gather(*tasks)

if __name__ == "__main__":
asyncio.run(main())

In this example, the print_numbers function is marked as an asynchronous coroutine using the async keyword. The await keyword is used to pause the execution of the coroutine and yield control to the event loop. In the main function, we create multiple tasks (each running the print_numbers function with a different number) and use asyncio.gather to execute them concurrently.

Worked Example

Let's explore an example of asynchronous file reading using Python 3.7's async/await feature:

import asyncio

async def read_file(filename):
with open(filename, 'r') as f:
lines = await f.readlines()
return lines

async def main():
files = ['file1.txt', 'file2.txt', 'file3.txt']
tasks = [read_file(f) for f in files]
results = await asyncio.gather(*tasks)
for result in results:
print('Contents of', result[0], ':\n', result[1])

if __name__ == "__main__":
asyncio.run(main())

In this example, we define an asynchronous function read_file that reads the contents of a file and returns its lines. In the main function, we create multiple tasks (one for each file) using list comprehension and use asyncio.gather to execute them concurrently. The results are then printed out.

Common Mistakes

  1. Misunderstanding async/await: Many developers new to asynchronous programming in Python make the mistake of treating async functions like synchronous functions, leading to blocked event loops and poor performance. Remember that async functions should perform I/O-bound tasks and yield control to the event loop using await.
  2. Incorrect use of type hints: Type hints can be a powerful tool for documenting your code, but incorrect usage (such as not specifying optional arguments) can lead to confusion or errors when working with third-party libraries.
  3. Ignoring the updated division behavior: If you're coming from Python 2.x, it's easy to forget that division in Python 3.7 now returns a float by default (e.g., 3 / 2 equals 1.5 instead of 1).
  4. Overlooking the standard library updates: The addition of new modules like typing, asyncio, and aiohttp can greatly simplify your code, but they may be overlooked if not properly documented or promoted.

Common Mistakes (Continued)

  1. Improper error handling: Asynchronous functions can make error handling more complex due to the non-blocking nature of the event loop. It's essential to use exception handling and ensure that errors are propagated correctly.
  2. Incorrect use of context managers: Context managers like async with should be used carefully, as improper usage can lead to resource leaks or other issues in asynchronous code.
  3. Ignoring performance considerations: Asynchronous programming requires careful consideration of performance implications, such as the number of concurrent tasks and the potential for increased memory usage.

Practice Questions

  1. Write an asynchronous function that reads lines from multiple files concurrently using async/await.
  2. Implement a simple web scraper using aiohttp and asyncio.
  3. Use type hints to document the parameters and return value of a custom function you create.
  4. Explain the difference between synchronous and asynchronous programming, and give an example of each in Python 3.7.
  5. Discuss proper error handling techniques for asynchronous functions in Python 3.7.
  6. Provide examples of when context managers should be used (and misused) in asynchronous code.
  7. Compare the performance implications of using too many concurrent tasks and insufficient concurrency in asynchronous programming with Python 3.7.

FAQ

  1. Why should I learn Python 3.7 if it's no longer supported?
  • Learning Python 3.7 can help you understand the basics of Python programming and provide a foundation for learning more recent versions like Python 3.8 and beyond.
  1. What are async/await in Python, and how do they work?
  • Async/await is used for asynchronous programming in Python, which allows concurrent execution of multiple tasks without blocking the main thread, improving overall performance.
  1. How can I use type hints to document my code effectively?
  • Type hints should be used to clearly document the parameters and return value of a function or method, making it easier for others (and yourself in the future) to understand your code.
  1. What are some common mistakes developers make when working with Python 3.7's async/await feature?
  • Developers often treat async functions like synchronous functions, leading to blocked event loops and poor performance. It's important to remember that async functions should perform I/O-bound tasks and yield control to the event loop using await.
  1. How does exception handling differ in asynchronous code compared to synchronous code?
  • In asynchronous code, exceptions must be handled properly to ensure they are propagated correctly through the event loop. This can involve using async context managers and ensuring that all tasks complete before the program terminates.
  1. What is a context manager in Python, and how should it be used (and misused) in asynchronous code?
  • A context manager is an object that defines the __enter__ and __exit__ methods to manage resources during the execution of a block of code. In asynchronous code, context managers should be used carefully, as improper usage can lead to resource leaks or other issues. Misuse might include forgetting to await the context manager or using it inappropriately with asynchronous functions.
  1. What are the performance implications of using too many concurrent tasks and insufficient concurrency in asynchronous programming with Python 3.7?
  • Using too many concurrent tasks can lead to increased memory usage, contention for resources, and decreased overall performance due to the event loop becoming overwhelmed. On the other hand, insufficient concurrency can result in poor utilization of available resources and suboptimal performance. It's essential to strike a balance between the number of concurrent tasks and the work they perform to achieve optimal performance.
Python 3.7 (EOL) | Python | XQA Learn