Python json库转储方法仅将空列表显示为单个列表的空数组



我正在使用json.dumps来转储我创建的类。有两个列表数据成员,一个从未使用过,但一个用于管理另一个数据成员列表的构建。从未使用过的列表不存在于生成的JSON中,但即使我从这些对象列表中的每个对象实例中清除了已使用的列表,也会添加该列表。我不希望JSON中有这个空列表。

在我返回要传递到转储的列表之前,我会执行以下

 for entry in self.endpointList:
     entry.attributeNameList.clear()

我也试着在自己的JSONEncoder中清理。当我在调试器中查看attributeNameList成员时,它们会被清除,但它们是由转储作为空数组发出的。其他未经处理的空列表永远不会显示。

另一个区别是,没有显示的空列表是以相同的方式声明的,但attributeNameList是在我的类的__init__方法中初始化的。

class ProvisioningEndpoint:
    attributeList = []
    attributeNameList = []
    def __init__(self, record):
         self.attributeNameList = list()

有没有办法防止这个特殊的空列表被转换成

"attributeNameList": []

attributeList从未添加到JSON输出中。

从未使用过的列表和已清除的列表在调试器中看起来完全相同——为空。Python可能在列表中有一个脏比特,并使用它来决定何时作为JSON发出。谢谢

这是编码器代码(根据要求)

 class ServiceRegistryEncoder(json.JSONEncoder):
        def default(self, obj):
            if isinstance(obj, (ProvisioningEndpoint,endpointAttribute)):
                obj = obj.__dict__

您的有两个属性,即列表attributeListAttributeNameList

类的实例具有attributeNameList作为属性,因为它是在__init__方法中初始化的。此实例属性覆盖类属性。

您的编码器正在序列化实例的__ dict__中的所有内容,其中将包括attributeNameList。如果你不想在self.attributeNameList为空时串行化,那么你需要在编码器中添加一些逻辑来处理这个问题:例如:

 class ServiceRegistryEncoder(json.JSONEncoder):
        def default(self, obj):
            if isinstance(obj, (ProvisioningEndpoint,endpointAttribute)):
                obj = obj.__dict__.copy()
                if not obj.get('attributeNameList):
                    try:
                        del obj['attributeNameList']
                    except KeyError:
                        pass

编辑:关于类属性的更多信息

当您尝试访问实例上的属性foo时,Python首先查看实例的__ dict__。如果在那里找不到该属性,Python将查找实例类的__dict__。如果它在那里找到了属性,就会返回它。这意味着类的所有实例都共享类属性。有关此方面的详细信息,请参阅教程。

由于类属性在实例之间共享,对类属性的更改将对所有实例可见。这可能会导致令人惊讶或不受欢迎的行为:

>>> class Emailer(object):
...     recipients = ['default@example']
...     def send_secret_email(self):
...         # send secret email
...         pass
... 
>>> e1 = Emailer()
>>> e2 = Emailer()
>>> e1.recipients.append('alice@example.com')
>>> print(e1.recipients)
['default@example', 'alice@example.com']
>>> e2.recipients.append('bob@example.com')
>>> print(e2.recipients)
['default@example', 'alice@example.com', 'bob@example.com']
>>> print(e1.recipients)
['default@example', 'alice@example.com', 'bob@example.com']

在类似上述示例的情况下,您可以在__init__方法中复制属性以减轻这种情况。

 >>> class Emailer(object):
...     recipients = ['default@example']
...     def __init__(self):
...         self.recipients = self.recipients.copy()
...     def send_secret_email(self):
...         # send secret email
...         pass
... 
>>> e1 = Emailer()
>>> e2 = Emailer()
>>> e1.recipients.append('alice@example.com')
>>> print(e1.recipients)
['default@example', 'alice@example.com']
>>> e2.recipients.append('bob@example.com')
>>> print(e2.recipients)
['default@example', 'bob@example.com']
>>> print(e1.recipients)
['default@example', 'alice@example.com']

正如@blackjack所观察到的,可变类属性通常是一种代码气味,但它们确实有一些用途:例如,如果一个类想要跟踪其实例。

最新更新