# 197. Contextlib's closing

`contextlib.closing` is a utility in the `contextlib` module that helps ensure resources such as files or sockets are properly closed when they are no longer needed, by automatically calling their `close()` method. It works in a context manager, ensuring that the resource is closed even if an exception occurs within the context.

Here are several Python code snippets demonstrating the use of `contextlib.closing` for safely handling and closing resources:

***

**1. Basic Example with File Handling**

```python
from contextlib import closing
import urllib.request

# Using closing to ensure the file is closed properly after use
with closing(open('example.txt', 'w')) as file:
    file.write("Hello, World!")
```

In this example, the file is opened and written to within the `with` block, and the `closing` context manager ensures that the file is automatically closed after the block is executed.

***

**2. Using closing with Socket**

```python
from contextlib import closing
import socket

# Example of using closing with socket
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
    sock.connect(('example.com', 80))
    sock.sendall(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
    response = sock.recv(1024)
    print(response.decode())
```

Here, `closing` ensures the socket is properly closed after the communication, even if an exception is raised during the request.

***

**3. Using closing with Database Connections**

```python
from contextlib import closing
import sqlite3

# Using closing with a database connection
with closing(sqlite3.connect('my_database.db')) as conn:
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM my_table')
    result = cursor.fetchall()
    print(result)
```

This ensures that the database connection is automatically closed after the database operations, preventing potential resource leakage.

***

**4. Using closing with a Custom Resource**

```python
from contextlib import closing

class CustomResource:
    def __enter__(self):
        print("Opening resource...")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Closing resource...")

# Using closing with a custom resource
with closing(CustomResource()) as resource:
    print("Using resource...")
```

In this example, the `closing` context manager wraps the `CustomResource`, ensuring the `__exit__` method is called, which closes the resource.

***

**5. Handling Multiple Resources Safely**

```python
from contextlib import closing
import os

# Using closing with multiple resources
with closing(open('file1.txt', 'w')) as file1, closing(open('file2.txt', 'w')) as file2:
    file1.write("Data for file 1")
    file2.write("Data for file 2")
```

This ensures both files are closed safely even if an error occurs while writing to one of them.

***

**6. Using closing for Network Resources**

```python
from contextlib import closing
import socket

# Ensuring the network connection is closed
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
    sock.connect(('localhost', 8080))
    sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
    response = sock.recv(1024)
    print(response.decode())
```

Using `closing` guarantees that the socket is closed properly after the communication.

***

**7. Using closing for a Web Request**

```python
from contextlib import closing
import urllib.request

# Closing after fetching a URL
with closing(urllib.request.urlopen('http://example.com')) as response:
    html = response.read()
    print(html[:100])  # Print first 100 characters of the response
```

This makes sure that the connection to the URL is closed after fetching the data, even if an exception occurs.

***

**8. Custom Context Manager for Closing Resources**

```python
from contextlib import closing

class Resource:
    def close(self):
        print("Resource closed.")

with closing(Resource()) as res:
    print("Resource is being used.")
```

This demonstrates using `closing` with a custom object that implements a `close()` method.

***

**9. Using closing for a Temporary File**

```python
from contextlib import closing
import tempfile

# Using closing with temporary file
with closing(tempfile.NamedTemporaryFile(delete=False)) as temp_file:
    temp_file.write(b"Temporary data")
    print(f"Temporary file created: {temp_file.name}")
```

The `closing` context manager ensures the temporary file is closed after use.

***

**10. Ensuring Network Connection Closes with Exceptions**

```python
from contextlib import closing
import socket

# Ensuring socket is closed even with exceptions
try:
    with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
        sock.connect(('localhost', 9000))
        sock.sendall(b"Hello server!")
        raise Exception("Something went wrong!")  # Simulate an exception
except Exception as e:
    print(f"Exception caught: {e}")
```

Even if an exception is raised during the communication, the `closing` context manager ensures that the socket is closed properly.

***

**Summary:**

* **`closing` Context Manager**: This is useful for any resource that has a `close()` method, like files, sockets, and database connections.
* **Automatic Cleanup**: Ensures that resources are closed after they are no longer needed, preventing resource leakage.
* **Handling Exceptions**: Even if an exception occurs inside the `with` block, the `close()` method will always be called when the block is exited.

Using `contextlib.closing` is a great way to manage resources, ensuring that they are properly cleaned up even if errors occur during their use.
