Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 不转换为集合的嵌套dict的差异_Python_Json_Recursion_Diff - Fatal编程技术网

Python 不转换为集合的嵌套dict的差异

Python 不转换为集合的嵌套dict的差异,python,json,recursion,diff,Python,Json,Recursion,Diff,在接下来的几个月里,我都会注意到这一点。 这是一个非常有趣的挑战。可以在许多上下文中用于传递大量json数据的系统 我对每个方法的预期输出进行了单元测试。 如果有人对解决这个问题的好算法或技术有什么建议, 单凭这一点就可以大有裨益 或者如果你有雄心壮志,你可以帮我解决:-) 这是单元测试 import unittest from diff import Diff class TestDiff(unittest.TestCase): def setUp(self): s

在接下来的几个月里,我都会注意到这一点。 这是一个非常有趣的挑战。可以在许多上下文中用于传递大量json数据的系统

我对每个方法的预期输出进行了单元测试。 如果有人对解决这个问题的好算法或技术有什么建议, 单凭这一点就可以大有裨益

或者如果你有雄心壮志,你可以帮我解决:-)

这是单元测试

import unittest
from diff import Diff

class TestDiff(unittest.TestCase):

    def setUp(self):
        self.old_dict = {"dict1":{"dict2": {"x":"A","z":"d"}}}
        self.new_dict = {"dict1":{"dict2": {"x":"C","y":"B"}}}
        self.d = Diff()

    def test_added_logic(self):
        result = self.d.added(self.old_dict, self.new_dict)
        expected = {"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"}
        self.assertEqual(result, expected)

    def test_modified_logic(self):
        result = self.d.modified(self.old_dict, self.new_dict)
        expected = {"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"}
        self.assertEqual(result, expected)

    def test_deleted_logic(self):
        result = self.d.deleted(self.old_dict, self.new_dict)
        expected = {"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}
        self.assertEqual(result, expected)

    def test_difference_logic(self):
        result = self.d.difference(self.old_dict, self.new_dict)
        expected = {"results":[
                        {"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"},
                        {"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"},
                        {"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}
            ]
        }
        self.assertEqual(result, expected)

if __name__ == "__main__":
    unittest.main()
import unittest
from diff import Diff

class TestDiff(unittest.TestCase):

    def setUp(self):
        self.old_dict = {"dict1":{"dict2": {"x":"A","z":"d"}}}
        self.new_dict = {"dict1":{"dict2": {"x":"C","y":"B"}}}
        self.old_flat = {"a":"a", "z":"z"}
        self.new_flat = {"a":"f", "b":"b"}

        self.d = Diff()

    def test_added_logic(self):
        result = self.d.added(self.old_dict, self.new_dict)
        expected = [{"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"}]
        self.assertEqual(result, expected)

    def test_added_flat_dict(self):
        result = self.d.added(self.old_flat, self.new_flat)
        expected = [{'field': 'b', 'operation': 'ADDED', 'new': 'b'}]
        self.assertEqual(result, expected)

    def test_modified_logic(self):
        result = self.d.modified(self.old_dict, self.new_dict)
        expected = [{"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"}]
        self.assertEqual(result, expected)

    def test_modified_flat_dict(self):
        result = self.d.modified(self.old_flat, self.new_flat)
        expected = [{'field': 'a', 'operation': 'MODIFIED', 'new': 'f', 'old': 'a'}]
        self.assertEqual(result, expected)

    def test_deleted_logic(self):
        result = self.d.deleted(self.old_dict, self.new_dict)
        expected = [{"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}]
        self.assertEqual(result, expected)

    def test_deleted_flat_dict(self):
        result = self.d.deleted(self.old_flat, self.new_flat)
        expected = [{'field': 'z', 'operation': 'DELETED', 'old': 'z'}]
        self.assertEqual(result, expected)

    def test_difference_logic(self):
        result = self.d.combine_results(self.old_dict, self.new_dict)
        expected = [
            {"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"},
            {"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"},
            {"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}
        ]
        self.assertEqual(result, expected)

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

我尝试了一下,通过了单元测试。在Python2.7中运行。然而,我将单元测试期望值更改为更加统一,它现在总是需要一个dict对象列表。否则,前三个测试对多重差异没有意义,最后一个测试不一致

欢迎提出改进建议

class Diff():
    """
    Show the difference between two given dicts 'old' and 'new'.

    Intended to be used in an auditing system that checks existing
    records in a nosql database ('old') and compares them with a
    request to update the record ('new') and store the difference
    in a separate database.

    See test_diff.py for expected output for each method.

    Will need recursive methods for nested dicts

    Use dot notation for the path to the key that is different e.g. {"a.b.c": "modified value"}

    Must not convert dicts to sets. Because of the billions of records that will be compared,
    conversion to sets, then back to dicts would drastically slow down the process.
    """

    def __init__(self):
        self.depth = []
        self.results = []

    def added(self, old, new):
        for key in new:
            if key not in old:
                self.results.append({
                    'operation': 'ADDED',
                    'field': '.'.join(self.depth) + '.' + str(key),
                    'new': new[key]
                })
            elif type(old[key]) == dict and type(new[key]) == dict:
                self.depth.append(str(key))
                self.added(old[key], new[key])

        if self.depth:
            self.depth.pop()
        else:
            return self.results

    def modified(self, old, new):
        for key in [key for key in new if key in old]:
            if type(old[key]) == dict and type(new[key]) == dict:
                self.depth.append(str(key))
                self.modified(old[key], new[key])
            elif old[key] != new[key]:
                self.results.append({
                    'operation': 'MODIFIED',
                    'field': '.'.join(self.depth) + '.' + str(key),
                    'old': old[key],
                    'new': new[key]
                })

        if self.depth:
            self.depth.pop()
        else:
            return self.results

    def deleted(self, old, new):
        for key in old:
            if key not in new:
                self.results.append({
                    'operation': 'DELETED',
                    'field': '.'.join(self.depth) + '.' + str(key),
                    'old': old[key]
                })
            elif type(old[key]) == dict and type(new[key]) == dict:
                self.depth.append(str(key))
                self.deleted(old[key], new[key])

        if self.depth:
            self.depth.pop()
        else:
            return self.results

    def difference(self, old, new):
        self.added(old, new)
        self.modified(old, new)
        self.deleted(old, new)
        return self.results

import unittest
from diff import Diff

class TestDiff(unittest.TestCase):

    def setUp(self):
        self.old_dict = {"dict1":{"dict2": {"x":"A","z":"d"}}}
        self.new_dict = {"dict1":{"dict2": {"x":"C","y":"B"}}}
        self.d = Diff()

    def test_added_logic(self):
        result = self.d.added(self.old_dict, self.new_dict)
        expected = [{"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"}]
        self.assertEqual(result, expected)

    def test_modified_logic(self):
        result = self.d.modified(self.old_dict, self.new_dict)
        expected = [{"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"}]
        self.assertEqual(result, expected)

    def test_deleted_logic(self):
        result = self.d.deleted(self.old_dict, self.new_dict)
        expected = [{"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}]
        self.assertEqual(result, expected)

    def test_difference_logic(self):
        result = self.d.difference(self.old_dict, self.new_dict)
        expected = [
            {"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"},
            {"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"},
            {"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}
        ]
        self.assertEqual(result, expected)

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

我尝试了一下,通过了单元测试。在Python2.7中运行。然而,我将单元测试期望值更改为更加统一,它现在总是需要一个dict对象列表。否则,前三个测试对多重差异没有意义,最后一个测试不一致

欢迎提出改进建议

class Diff():
    """
    Show the difference between two given dicts 'old' and 'new'.

    Intended to be used in an auditing system that checks existing
    records in a nosql database ('old') and compares them with a
    request to update the record ('new') and store the difference
    in a separate database.

    See test_diff.py for expected output for each method.

    Will need recursive methods for nested dicts

    Use dot notation for the path to the key that is different e.g. {"a.b.c": "modified value"}

    Must not convert dicts to sets. Because of the billions of records that will be compared,
    conversion to sets, then back to dicts would drastically slow down the process.
    """

    def __init__(self):
        self.depth = []
        self.results = []

    def added(self, old, new):
        for key in new:
            if key not in old:
                self.results.append({
                    'operation': 'ADDED',
                    'field': '.'.join(self.depth) + '.' + str(key),
                    'new': new[key]
                })
            elif type(old[key]) == dict and type(new[key]) == dict:
                self.depth.append(str(key))
                self.added(old[key], new[key])

        if self.depth:
            self.depth.pop()
        else:
            return self.results

    def modified(self, old, new):
        for key in [key for key in new if key in old]:
            if type(old[key]) == dict and type(new[key]) == dict:
                self.depth.append(str(key))
                self.modified(old[key], new[key])
            elif old[key] != new[key]:
                self.results.append({
                    'operation': 'MODIFIED',
                    'field': '.'.join(self.depth) + '.' + str(key),
                    'old': old[key],
                    'new': new[key]
                })

        if self.depth:
            self.depth.pop()
        else:
            return self.results

    def deleted(self, old, new):
        for key in old:
            if key not in new:
                self.results.append({
                    'operation': 'DELETED',
                    'field': '.'.join(self.depth) + '.' + str(key),
                    'old': old[key]
                })
            elif type(old[key]) == dict and type(new[key]) == dict:
                self.depth.append(str(key))
                self.deleted(old[key], new[key])

        if self.depth:
            self.depth.pop()
        else:
            return self.results

    def difference(self, old, new):
        self.added(old, new)
        self.modified(old, new)
        self.deleted(old, new)
        return self.results

import unittest
from diff import Diff

class TestDiff(unittest.TestCase):

    def setUp(self):
        self.old_dict = {"dict1":{"dict2": {"x":"A","z":"d"}}}
        self.new_dict = {"dict1":{"dict2": {"x":"C","y":"B"}}}
        self.d = Diff()

    def test_added_logic(self):
        result = self.d.added(self.old_dict, self.new_dict)
        expected = [{"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"}]
        self.assertEqual(result, expected)

    def test_modified_logic(self):
        result = self.d.modified(self.old_dict, self.new_dict)
        expected = [{"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"}]
        self.assertEqual(result, expected)

    def test_deleted_logic(self):
        result = self.d.deleted(self.old_dict, self.new_dict)
        expected = [{"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}]
        self.assertEqual(result, expected)

    def test_difference_logic(self):
        result = self.d.difference(self.old_dict, self.new_dict)
        expected = [
            {"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"},
            {"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"},
            {"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}
        ]
        self.assertEqual(result, expected)

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

感谢mike.k解决了这个问题 我对代码做了一些修改。 我增加了平面、一级深度的测试。 我还固定了平面dicts深度前的点。 最后,因为输出将转换为json 为了存储在数据库中,我又添加了一个方法 将最后的差值转换为dict

class Diff():
    """
    Show the difference between two given dicts 'old' and 'new'.

    Intended to be used in an auditing system that checks existing
    records in a nosql database ('old') and compares them with a
    request to update the record ('new') and store the difference
    in a separate database.

    See test_diff.py for expected output for each method.

    Will need recursive methods for nested dicts

    Use dot notation for the path to the key that is different e.g. {"a.b.c": "modified value"}

    Must not convert dicts to sets. Because of the billions of records that will be compared,
    conversion to sets, then back to dicts would drastically slow down the process.
    """

    def __init__(self):
        self.depth = []
        self.results = []

    def added(self, old, new):
        for key in new:
            if key not in old:
                if self.depth:
                    self.results.append({
                        'operation': 'ADDED',
                        'field': '.'.join(self.depth) + '.' + str(key),
                        'new': new[key]
                    })
                else:
                    self.results.append({
                        'operation': 'ADDED',
                        'field': str(key),
                        'new': new[key]
                    })
            else:
                if type(old[key]) == dict and type(new[key]) == dict:
                    self.depth.append(str(key))
                    self.added(old[key], new[key])

        if self.depth:
            self.depth.pop()
        else:
            return self.results

    def modified(self, old, new):
        for key in [key for key in new if key in old]:
            if type(old[key]) == dict and type(new[key]) == dict:
                self.depth.append(str(key))
                self.modified(old[key], new[key])

            elif old[key] != new[key]:
                if self.depth:
                    self.results.append({
                        'operation': 'MODIFIED',
                        'field': '.'.join(self.depth) + '.' + str(key),
                        'old': old[key],
                        'new': new[key]
                    })
                else:
                    self.results.append({
                        'operation': 'MODIFIED',
                        'field': str(key),
                        'old': old[key],
                        'new': new[key]
                    })

        if self.depth:
            self.depth.pop()
        else:
            return self.results

    def deleted(self, old, new):
        for key in old:
            if key not in new:
                if self.depth:
                    self.results.append({
                        'operation': 'DELETED',
                        'field': '.'.join(self.depth) + '.' + str(key),
                        'old': old[key]
                    })
                else:
                    self.results.append({
                        'operation': 'DELETED',
                        'field': str(key),
                        'old': old[key]
                    })
            else:
                if type(old[key]) == dict and type(new[key]) == dict:
                    self.depth.append(str(key))
                    self.deleted(old[key], new[key])

        if self.depth:
            self.depth.pop()
        else:
            return self.results

    def combine_results(self, old, new):
        self.added(old, new)
        self.modified(old, new)
        self.deleted(old, new)
        return self.results

    def difference(self, old, new):
        d = {}
        d['difference'] = self.combine_results(old, new)
        return d
这是单元测试

import unittest
from diff import Diff

class TestDiff(unittest.TestCase):

    def setUp(self):
        self.old_dict = {"dict1":{"dict2": {"x":"A","z":"d"}}}
        self.new_dict = {"dict1":{"dict2": {"x":"C","y":"B"}}}
        self.d = Diff()

    def test_added_logic(self):
        result = self.d.added(self.old_dict, self.new_dict)
        expected = {"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"}
        self.assertEqual(result, expected)

    def test_modified_logic(self):
        result = self.d.modified(self.old_dict, self.new_dict)
        expected = {"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"}
        self.assertEqual(result, expected)

    def test_deleted_logic(self):
        result = self.d.deleted(self.old_dict, self.new_dict)
        expected = {"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}
        self.assertEqual(result, expected)

    def test_difference_logic(self):
        result = self.d.difference(self.old_dict, self.new_dict)
        expected = {"results":[
                        {"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"},
                        {"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"},
                        {"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}
            ]
        }
        self.assertEqual(result, expected)

if __name__ == "__main__":
    unittest.main()
import unittest
from diff import Diff

class TestDiff(unittest.TestCase):

    def setUp(self):
        self.old_dict = {"dict1":{"dict2": {"x":"A","z":"d"}}}
        self.new_dict = {"dict1":{"dict2": {"x":"C","y":"B"}}}
        self.old_flat = {"a":"a", "z":"z"}
        self.new_flat = {"a":"f", "b":"b"}

        self.d = Diff()

    def test_added_logic(self):
        result = self.d.added(self.old_dict, self.new_dict)
        expected = [{"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"}]
        self.assertEqual(result, expected)

    def test_added_flat_dict(self):
        result = self.d.added(self.old_flat, self.new_flat)
        expected = [{'field': 'b', 'operation': 'ADDED', 'new': 'b'}]
        self.assertEqual(result, expected)

    def test_modified_logic(self):
        result = self.d.modified(self.old_dict, self.new_dict)
        expected = [{"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"}]
        self.assertEqual(result, expected)

    def test_modified_flat_dict(self):
        result = self.d.modified(self.old_flat, self.new_flat)
        expected = [{'field': 'a', 'operation': 'MODIFIED', 'new': 'f', 'old': 'a'}]
        self.assertEqual(result, expected)

    def test_deleted_logic(self):
        result = self.d.deleted(self.old_dict, self.new_dict)
        expected = [{"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}]
        self.assertEqual(result, expected)

    def test_deleted_flat_dict(self):
        result = self.d.deleted(self.old_flat, self.new_flat)
        expected = [{'field': 'z', 'operation': 'DELETED', 'old': 'z'}]
        self.assertEqual(result, expected)

    def test_difference_logic(self):
        result = self.d.combine_results(self.old_dict, self.new_dict)
        expected = [
            {"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"},
            {"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"},
            {"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}
        ]
        self.assertEqual(result, expected)

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

感谢mike.k解决了这个问题 我对代码做了一些修改。 我增加了平面、一级深度的测试。 我还固定了平面dicts深度前的点。 最后,因为输出将转换为json 为了存储在数据库中,我又添加了一个方法 将最后的差值转换为dict

class Diff():
    """
    Show the difference between two given dicts 'old' and 'new'.

    Intended to be used in an auditing system that checks existing
    records in a nosql database ('old') and compares them with a
    request to update the record ('new') and store the difference
    in a separate database.

    See test_diff.py for expected output for each method.

    Will need recursive methods for nested dicts

    Use dot notation for the path to the key that is different e.g. {"a.b.c": "modified value"}

    Must not convert dicts to sets. Because of the billions of records that will be compared,
    conversion to sets, then back to dicts would drastically slow down the process.
    """

    def __init__(self):
        self.depth = []
        self.results = []

    def added(self, old, new):
        for key in new:
            if key not in old:
                if self.depth:
                    self.results.append({
                        'operation': 'ADDED',
                        'field': '.'.join(self.depth) + '.' + str(key),
                        'new': new[key]
                    })
                else:
                    self.results.append({
                        'operation': 'ADDED',
                        'field': str(key),
                        'new': new[key]
                    })
            else:
                if type(old[key]) == dict and type(new[key]) == dict:
                    self.depth.append(str(key))
                    self.added(old[key], new[key])

        if self.depth:
            self.depth.pop()
        else:
            return self.results

    def modified(self, old, new):
        for key in [key for key in new if key in old]:
            if type(old[key]) == dict and type(new[key]) == dict:
                self.depth.append(str(key))
                self.modified(old[key], new[key])

            elif old[key] != new[key]:
                if self.depth:
                    self.results.append({
                        'operation': 'MODIFIED',
                        'field': '.'.join(self.depth) + '.' + str(key),
                        'old': old[key],
                        'new': new[key]
                    })
                else:
                    self.results.append({
                        'operation': 'MODIFIED',
                        'field': str(key),
                        'old': old[key],
                        'new': new[key]
                    })

        if self.depth:
            self.depth.pop()
        else:
            return self.results

    def deleted(self, old, new):
        for key in old:
            if key not in new:
                if self.depth:
                    self.results.append({
                        'operation': 'DELETED',
                        'field': '.'.join(self.depth) + '.' + str(key),
                        'old': old[key]
                    })
                else:
                    self.results.append({
                        'operation': 'DELETED',
                        'field': str(key),
                        'old': old[key]
                    })
            else:
                if type(old[key]) == dict and type(new[key]) == dict:
                    self.depth.append(str(key))
                    self.deleted(old[key], new[key])

        if self.depth:
            self.depth.pop()
        else:
            return self.results

    def combine_results(self, old, new):
        self.added(old, new)
        self.modified(old, new)
        self.deleted(old, new)
        return self.results

    def difference(self, old, new):
        d = {}
        d['difference'] = self.combine_results(old, new)
        return d
这是单元测试

import unittest
from diff import Diff

class TestDiff(unittest.TestCase):

    def setUp(self):
        self.old_dict = {"dict1":{"dict2": {"x":"A","z":"d"}}}
        self.new_dict = {"dict1":{"dict2": {"x":"C","y":"B"}}}
        self.d = Diff()

    def test_added_logic(self):
        result = self.d.added(self.old_dict, self.new_dict)
        expected = {"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"}
        self.assertEqual(result, expected)

    def test_modified_logic(self):
        result = self.d.modified(self.old_dict, self.new_dict)
        expected = {"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"}
        self.assertEqual(result, expected)

    def test_deleted_logic(self):
        result = self.d.deleted(self.old_dict, self.new_dict)
        expected = {"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}
        self.assertEqual(result, expected)

    def test_difference_logic(self):
        result = self.d.difference(self.old_dict, self.new_dict)
        expected = {"results":[
                        {"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"},
                        {"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"},
                        {"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}
            ]
        }
        self.assertEqual(result, expected)

if __name__ == "__main__":
    unittest.main()
import unittest
from diff import Diff

class TestDiff(unittest.TestCase):

    def setUp(self):
        self.old_dict = {"dict1":{"dict2": {"x":"A","z":"d"}}}
        self.new_dict = {"dict1":{"dict2": {"x":"C","y":"B"}}}
        self.old_flat = {"a":"a", "z":"z"}
        self.new_flat = {"a":"f", "b":"b"}

        self.d = Diff()

    def test_added_logic(self):
        result = self.d.added(self.old_dict, self.new_dict)
        expected = [{"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"}]
        self.assertEqual(result, expected)

    def test_added_flat_dict(self):
        result = self.d.added(self.old_flat, self.new_flat)
        expected = [{'field': 'b', 'operation': 'ADDED', 'new': 'b'}]
        self.assertEqual(result, expected)

    def test_modified_logic(self):
        result = self.d.modified(self.old_dict, self.new_dict)
        expected = [{"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"}]
        self.assertEqual(result, expected)

    def test_modified_flat_dict(self):
        result = self.d.modified(self.old_flat, self.new_flat)
        expected = [{'field': 'a', 'operation': 'MODIFIED', 'new': 'f', 'old': 'a'}]
        self.assertEqual(result, expected)

    def test_deleted_logic(self):
        result = self.d.deleted(self.old_dict, self.new_dict)
        expected = [{"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}]
        self.assertEqual(result, expected)

    def test_deleted_flat_dict(self):
        result = self.d.deleted(self.old_flat, self.new_flat)
        expected = [{'field': 'z', 'operation': 'DELETED', 'old': 'z'}]
        self.assertEqual(result, expected)

    def test_difference_logic(self):
        result = self.d.combine_results(self.old_dict, self.new_dict)
        expected = [
            {"operation": "ADDED", "field": "dict1.dict2.y", "new": "B"},
            {"operation": "MODIFIED", "field": "dict1.dict2.x", "old": "A", "new": "C"},
            {"operation": "DELETED", "field": "dict1.dict2.z", "old": "d"}
        ]
        self.assertEqual(result, expected)

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

基于@mike-k答案,我创建了一个不需要创建新类的方法

实施 如果您想要更高的性能,但不需要排序,您可以删除
sorted()
,或者使用
yield
而不是
return来实现此方法,以获得
生成器
而不是
列表

博士 未设置
的实施
如果您确实需要一个没有
set
的实现,您可以执行以下操作

def dict_diff(dict1: dict, dict2: dict, operation='modified', keys=None):
    acceptable_methods = ('added', 'deleted', 'modified')
    if operation not in acceptable_methods:
        raise ValueError('parameter `operation` should be on of %s' % str(acceptable_methods))
    dict_diff_result = namedtuple('DictDiffResult', ('key', 'dict1_value', 'dict2_value', 'operation'))
    if keys is None:
        keys = list()
    diffs = list()

    for key in dict1:
        key_list = keys + [key]
        if key not in dict2:
            if operation in ('deleted', 'modified',):
                diffs.append(dict_diff_result(keys + [key], dict1[key], None, 'deleted'))
        else:
            dict1_val = dict1[key]
            dict2_val = dict2[key]
            if isinstance(dict1_val, dict) and isinstance(dict2_val, dict):
                results = dict_diff(dict1_val, dict2_val, keys=key_list, operation=operation)
                diffs += results
            elif dict1_val != dict2_val and operation == 'modified':
                diffs.append(dict_diff_result(key_list, dict1_val, dict2_val, 'modified'))
    for key in dict2:
        if key not in dict1:
            if operation in ('added', 'modified',):
                diffs.append(dict_diff_result(keys + [key], None, dict2[key], 'added'))

    return diffs
因为它会在整个dict2上迭代,所以对于具有许多类似值的长dict2来说,这可能会比较慢


关于第二个方法的一个小细节是,它不再被排序,但是可以很容易地更改

基于@mike-k answer,我创建了一个不需要创建新类的方法

实施 如果您想要更高的性能,但不需要排序,您可以删除
sorted()
,或者使用
yield
而不是
return来实现此方法,以获得
生成器
而不是
列表

博士 未设置
的实施
如果您确实需要一个没有
set
的实现,您可以执行以下操作

def dict_diff(dict1: dict, dict2: dict, operation='modified', keys=None):
    acceptable_methods = ('added', 'deleted', 'modified')
    if operation not in acceptable_methods:
        raise ValueError('parameter `operation` should be on of %s' % str(acceptable_methods))
    dict_diff_result = namedtuple('DictDiffResult', ('key', 'dict1_value', 'dict2_value', 'operation'))
    if keys is None:
        keys = list()
    diffs = list()

    for key in dict1:
        key_list = keys + [key]
        if key not in dict2:
            if operation in ('deleted', 'modified',):
                diffs.append(dict_diff_result(keys + [key], dict1[key], None, 'deleted'))
        else:
            dict1_val = dict1[key]
            dict2_val = dict2[key]
            if isinstance(dict1_val, dict) and isinstance(dict2_val, dict):
                results = dict_diff(dict1_val, dict2_val, keys=key_list, operation=operation)
                diffs += results
            elif dict1_val != dict2_val and operation == 'modified':
                diffs.append(dict_diff_result(key_list, dict1_val, dict2_val, 'modified'))
    for key in dict2:
        if key not in dict1:
            if operation in ('added', 'modified',):
                diffs.append(dict_diff_result(keys + [key], None, dict2[key], 'added'))

    return diffs
因为它会在整个dict2上迭代,所以对于具有许多类似值的长dict2来说,这可能会比较慢


关于第二种方法的一个小细节是,它不再排序,但可以很容易地更改

您如何比较?所有的dict都有相同的结构,只是键不同吗?你怎么比较?所有的dict都有相同的结构,只是键不同吗?你怎么比较?所有的dicts都有相同的结构只是不同的键吗?迈克,你太棒了。这太完美了。昨晚我把这件事搞了两个小时,感觉我的大脑在融化。我会研究你的方法。迈克,你太棒了。这太完美了。昨晚我把这件事搞了两个小时,感觉我的大脑在融化。我会研究你的方法。迈克,你太棒了。这太完美了。昨晚我把这件事搞了两个小时,感觉我的大脑在融化。我将研究你的方法。简化部分的建议:
'field':('..join(self.depth)+'.if-depth-else'')+str(key)
简化部分的建议:
'field':('.'.join(self.depth)+'.if-depth-else'')+str简化部分的建议:
'field:('..join(self.depth)'.'+'.'if depth else')+str(键)