如何以Pythonic方式为json.loads传递两个object_pairs_hook参数?
json.loads' object_pairs_hook First off, your current code will throw a SyntaxError right away—Python doesn’t let you pass the same keyword argument twice (even if it didn’t error, the second object_pairs_hook would overwrite the first, which isn’t what you want). The fix here is to create a single hook that handles both requirements: preserving duplicate keys AND maintaining the original order of the JSON input.
Let’s walk through two clean, Pythonic approaches:
1. Create a Custom Class Inheriting from OrderedDict
If you already have a KeepDuplicates class, you can modify it to inherit from OrderedDict (from the collections module) so it retains order while handling duplicates. Here’s how that might look:
from collections import OrderedDict import json class OrderedKeepDuplicates(OrderedDict): def __setitem__(self, key, value): # Handle duplicate keys: convert existing value to a list if needed if key in self: if isinstance(self[key], list): self[key].append(value) else: self[key] = [self[key], value] else: # Use OrderedDict's default behavior for new keys super().__setitem__(key, value) # Usage example json_value = '{"a": 1, "b": 2, "a": 3}' raw_data = json.loads(json_value, object_pairs_hook=OrderedKeepDuplicates) print(raw_data) # Output: OrderedKeepDuplicates([('a', [1, 3]), ('b', 2)])
This class inherits all the order-preserving behavior of OrderedDict and adds logic to keep duplicate keys by storing their values in a list.
2. Use a Custom Hook Function
If you prefer not to create a new class, you can write a function that processes the key-value pairs directly, builds an ordered structure, and handles duplicates:
from collections import OrderedDict import json def ordered_keep_duplicates(pairs): result = OrderedDict() for key, value in pairs: if key in result: # Append to list if key already exists if isinstance(result[key], list): result[key].append(value) else: result[key] = [result[key], value] else: result[key] = value return result # Usage example json_value = '{"a": 1, "b": 2, "a": 3}' raw_data = json.loads(json_value, object_pairs_hook=ordered_keep_duplicates) print(raw_data) # Output: OrderedDict([('a', [1, 3]), ('b', 2)])
Note for Python 3.7+ Users
Starting with Python 3.7, regular dict objects preserve insertion order by default. If you don’t need to support older versions, you can simplify the code by replacing OrderedDict with a standard dict:
import json def keep_duplicates(pairs): result = {} for key, value in pairs: if key in result: if isinstance(result[key], list): result[key].append(value) else: result[key] = [result[key], value] else: result[key] = value return result # Usage json_value = '{"a": 1, "b": 2, "a": 3}' raw_data = json.loads(json_value, object_pairs_hook=keep_duplicates) print(raw_data) # Output: {'a': [1, 3], 'b': 2} (order preserved in Python 3.7+)
The core idea here is that object_pairs_hook expects a single callable (class or function) that takes the list of (key, value) pairs from the JSON parser and returns the desired dictionary-like object. By combining both behaviors into one callable, you get exactly what you need.
内容的提问来源于stack exchange,提问作者Lowpe

