【问题标题】:Get rid of Python private indicating prefixes摆脱 Python 私有指示前缀
【发布时间】:2020-06-01 16:12:44
【问题描述】:

我有一个这样的自定义类:

import json

class Config:
    def __init__(self):
        self._field1 = None
        self._field2 = None

    @property
    def field1(self):
        return self._field1

    @field1.setter
    def field1(self, value):
        self._field1 = value

    @property
    def field2(self):
        return self._field2

    @field2.setter
    def field2(self, value):
        self._field2 = value

    def validate(self):
        fields = [attribute for attribute in dir(self) if not attribute.startswith('__') and not callable(getattr(self, attribute))]
        for field in fields:
            if getattr(self, field) == None:
                raise AttributeError("You must set all fields, " + str(field) + " is not set")

    def toJSON(self):
        return json.dumps(self, default=lambda o: vars(o), 
            sort_keys=True, indent=4)

如你所见,我尝试对我的类进行 JSON 序列化,但它总是会在 json 中包含 _ 前缀(因为 vars 会返回它)

问题 1:我怎样才能摆脱它?

问题 2:我尝试从类中删除 _ 前缀,但在调用构造函数时会收到“错误:调用 Python 对象时超出最大递归深度”。为什么会这样?

稍后我可能会向设置器添加验证逻辑。

另外,如果您对如何重构我的代码有任何建议,请不要私信。

【问题讨论】:

  • 为什么需要 __ ??这是必需的吗?
  • 这能回答你的问题吗? stackoverflow.com/a/31813203/12479639
  • 递归错误的出现是因为在构造函数中,你初始化了变量,从而调用了setter函数。这些函数会更改变量中的值,因此调用 setter 函数等
  • @Akhilesh _ 应该表示一个私有字段,因为稍后我想向设置器添加验证逻辑,并且我不希望在此之外修改实例变量。
  • @EdWard 你能告诉我为什么这里会发生这种情况而不是“私人”领域吗?我没有找到任何文档。

标签: python json python-3.x private


【解决方案1】:

这可能有点矫枉过正,但这是可行的:

import json

class _ConfigSerializable:
    __dict__ = {}
    def __init__(self, config):
        for x, y in config.__dict__.items():
            while x.startswith("_"):
                x = x[1:]
            self.__dict__[x] = y

class Config:
    def __init__(self):
        self._field1 = None
        self._field2 = None

    @property
    def field1(self):
        return self._field1

    @field1.setter
    def field1(self, value):
        self._field1 = value

    @property
    def field2(self):
        return self._field2

    @field2.setter
    def field2(self, value):
        self._field2 = value

    def validate(self):
        fields = [attribute for attribute in dir(self) if not attribute.startswith('__') and not callable(getattr(self, attribute))]
        for field in fields:
            if getattr(self, field) == None:
                raise AttributeError("You must set all fields, " + str(field) + " is not set")

    def toJSON(self):
        s = _ConfigSerializable(self)
        return json.dumps(s, default=lambda o: vars(o), 
            sort_keys=True, indent=4)

print(Config().toJSON())

输出:

{
    "field1": null,
    "field2": null
}

基本上,我们创建一个新类,它接受配置实例的属性,并创建一个字典,删除任何属性名称开头的_。然后我们将这个类实例序列化。

【讨论】:

  • 这是比这更好的方法吗? stackoverflow.com/a/31813187/10320604
  • 由你决定。我的方法有效,我想更容易扩展,但答案是更少的代码,并且可能更有效。 :)
猜你喜欢
  • 2017-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-10
  • 2011-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多