# 71. Handling JSON Data

**1. Parsing JSON from a String**

Parsing a JSON string into a Python dictionary.

```python
import json

json_string = '{"name": "Alice", "age": 30}'
parsed_data = json.loads(json_string)

print(parsed_data)  # Output: {'name': 'Alice', 'age': 30}
```

***

**2. Converting Python Dictionary to JSON String**

Converting a Python dictionary into a JSON-formatted string.

```python
import json

data = {"name": "Bob", "age": 25}
json_string = json.dumps(data)

print(json_string)  # Output: {"name": "Bob", "age": 25}
```

***

**3. Reading JSON from a File**

Reading JSON data from a file and converting it into a Python dictionary.

```python
import json

with open('data.json', 'r') as file:
    data = json.load(file)

print(data)  # Output will depend on the content of 'data.json'
```

***

**4. Writing JSON to a File**

Writing a Python dictionary to a JSON file.

```python
import json

data = {"name": "Charlie", "age": 35}

with open('output.json', 'w') as file:
    json.dump(data, file)
```

***

**5. Pretty-Printing JSON Data**

Formatting JSON data for readability with indentation.

```python
import json

data = {"name": "Dave", "age": 40}
json_string = json.dumps(data, indent=4)

print(json_string)  
# Output: 
# {
#     "name": "Dave",
#     "age": 40
# }
```

***

**6. Converting Python Lists to JSON**

Converting a Python list to a JSON-formatted string.

```python
import json

data = [1, 2, 3, 4, 5]
json_string = json.dumps(data)

print(json_string)  # Output: [1, 2, 3, 4, 5]
```

***

**7. Handling Non-ASCII Characters in JSON**

Ensuring non-ASCII characters are properly handled when converting to JSON.

```python
import json

data = {"greeting": "안녕하세요"}
json_string = json.dumps(data, ensure_ascii=False)

print(json_string)  # Output: {"greeting": "안녕하세요"}
```

***

**8. Customizing JSON Serialization**

Customizing the way objects are serialized by using a custom `default` function.

```python
import json
from datetime import datetime

def default_serializer(obj):
    if isinstance(obj, datetime):
        return obj.isoformat()
    raise TypeError(f"Type {type(obj)} not serializable")

data = {"event": datetime(2024, 8, 1, 14, 30)}

json_string = json.dumps(data, default=default_serializer)

print(json_string)  # Output: {"event": "2024-08-01T14:30:00"}
```

***

**9. Handling JSON with Nested Structures**

Parsing and working with JSON data that contains nested structures.

```python
import json

json_string = '{"name": "Eve", "address": {"city": "New York", "zip": "10001"}}'
data = json.loads(json_string)

print(data['address']['city'])  # Output: New York
```

***

**10. Deserializing JSON with Custom Classes**

Converting JSON data into custom Python objects by subclassing `json.JSONDecoder`.

```python
import json

class CustomDecoder(json.JSONDecoder):
    def decode(self, s, **kwargs):
        data = super().decode(s, **kwargs)
        data['name'] = data['name'].upper()  # Modify the 'name' field
        return data

json_string = '{"name": "Alice", "age": 30}'
data = json.loads(json_string, cls=CustomDecoder)

print(data)  # Output: {'name': 'ALICE', 'age': 30}
```

***

These snippets show how to handle JSON data in Python, including parsing, creating, reading, and writing JSON. The examples also cover customization options for handling non-ASCII characters, nested structures, and more complex serialization and deserialization scenarios.
