【问题标题】:Python json library dumps method shows empty lists as empty array for a single list onlyPython json库转储方法仅将空列表显示为单个列表的空数组
【发布时间】:2016-04-05 12:53:06
【问题描述】:

我正在使用 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__

【问题讨论】:

    标签: python json python-3.x


    【解决方案1】:

    您的 class 有两个属性是列表 - attributeListAttributeNameList

    类的

    Instances 具有 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 __ 中查找。如果它在那里找到属性,它将返回它。这意味着类属性在类的所有实例之间共享。有关更多信息,请参阅the tutorial

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

    >>> 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 所观察到的,可变类属性通常是一种代码味道,但它们确实有一些用途:例如,如果一个类想要跟踪它的实例。

    【讨论】:

    • 谢谢。那么,类属性,如果没有在__init__方法中设置,实例中就不存在了?
    • @ThomasBentley 类属性从不存在于实例中。如果您在__init__ 中设置了同名的属性,那么您在类中有一个类属性,在实例中有一个同名的实例属性。不是常量的类属性通常是代码异味。
    • 谢谢二十一点。它们的类属性和实例属性将以相同的方式显示在调试器中,对吗?这就是我在 pydev 中看到的。
    猜你喜欢
    • 1970-01-01
    • 2014-01-12
    • 2014-09-30
    • 2019-10-01
    • 2020-07-20
    • 2016-07-01
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多