Python 基于uuu setattr和u getattr的动态配置对象__

Python 基于uuu setattr和u getattr的动态配置对象__,python,Python,我试图创建动态对象来验证我在飞行中的配置,并将结果显示为对象。我试图通过创建这样的类来实现这一点: class SubConfig(object): def __init__(self, config, key_types): self.__config = config self.__values = {} self.__key_types = key_types def __getattr__(self, item):

我试图创建动态对象来验证我在飞行中的配置,并将结果显示为对象。我试图通过创建这样的类来实现这一点:

class SubConfig(object):
    def __init__(self, config, key_types):
        self.__config = config
        self.__values = {}
        self.__key_types = key_types

    def __getattr__(self, item):
        if item in self.__key_types:
            return self.__values[item] or None
        else:
            raise ValueError("No such item to get from config")

    def __setattr__(self, item, value):
        if self.__config._blocked:
            raise ValueError("Can't change values after service has started")

        if item in self.__key_types:
            if type(value) in self.__key_types[item]:
                self.__values[item] = value
            else:
                raise ValueError("Can't assing value in different type then declared!")
        else:
            raise ValueError("No such item to set in config")
SubcoFig是配置文件中节的包装器。Config具有在程序启动后更改值的开关终止可能性(您只能在初始化时更改值)

问题是当我在getattr中设置它在无穷循环中得到的任何值时。正如我读到的
\uuuuu getattr\uuuuu
不应该这样做(首先获取现有attr,然后调用
\uuuuu getattr\uuuuu
)。我将我的代码与可用的示例进行了比较,但我什么也找不到


我注意到所有问题都是由我的构造函数生成的。

问题是,初始化对象时,构造函数调用
\uuuu setattr\uuuu
,然后调用
\uu getattr\uuuu
,因为私有成员尚未初始化

我可以想出两种方法来解决这个问题:

一种选择是调用
对象。\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。您还可以直接在
self.\uu dict\uu
中设置值。这里的一个问题是,由于使用了双下划线,因此必须手动更改属性名称(因此
“\uuuu config”
变成
”\uu config”
):

另一种方法是让
\uuuuu setattr\uuuuuuuuuuuuuuuuuuuuuuuuuuuu>检测并传递对以
\uuuuuuu
开头的属性名称的访问,即

if item.startswith('_')
    return super(SubConfig, self).__setattr__(item, value)

如果有人有很好的理由访问对象的内部,你就没有理由试图阻止他们。问题是初始化对象时的构造函数调用了,然后调用
\uuuu getattr\uuuu
,因为
\uuuu
私有成员尚未初始化

我可以想出两种方法来解决这个问题:

一种选择是调用
对象。\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。您还可以直接在
self.\uu dict\uu
中设置值。这里的一个问题是,由于使用了双下划线,因此必须手动更改属性名称(因此
“\uuuu config”
变成
”\uu config”
):

另一种方法是让
\uuuuu setattr\uuuuuuuuuuuuuuuuuuuuuuuuuuuu>检测并传递对以
\uuuuuuu
开头的属性名称的访问,即

if item.startswith('_')
    return super(SubConfig, self).__setattr__(item, value)

如果有人有很好的理由访问你的对象的内部,那么这就更像是python,您没有理由试图阻止它们。

Cf ecatmur对根本原因的回答-请记住,
\uuuuuSetAttr\uuuuuuuuuuu
\uuuGetAttr\uuuuuuuuuuuuuuuuuuuuuu\uuuuuuuuuuuuuuu>并不对称-每次尝试绑定对象属性时都会无条件地调用它。重写
\uuuu setattr\uuuuuu
是一件棘手的事情,如果您不清楚其利弊,就不应该这样做

现在为您的用例提供一个简单实用的解决方案:重写初始值设定项以避免触发setattr调用:

class SubConfig(object):
    def __init__(self, config, key_types):
        self.__dict__.update(
            _SubConfig__config=config,
            _SubConfig__values={},
            _SubConfig__key_types=key_types
            )

请注意,我重命名了属性,以模拟使用双前导下划线命名方案时发生的名称损坏

Cf ecatmur对根本原因的回答-请记住,
\uuuuu setattr\uuuuuuu
\uuuu getattr\uuuuuuu
不是对称的-它是在每次尝试绑定对象属性时无条件调用的。重写
\uuuu setattr\uuuuuu
是一件棘手的事情,如果您不清楚其利弊,就不应该这样做

现在为您的用例提供一个简单实用的解决方案:重写初始值设定项以避免触发setattr调用:

class SubConfig(object):
    def __init__(self, config, key_types):
        self.__dict__.update(
            _SubConfig__config=config,
            _SubConfig__values={},
            _SubConfig__key_types=key_types
            )

请注意,我重命名了属性,以模拟使用双前导下划线命名方案时发生的名称损坏

感谢您的建议,解决方案是将所有设置器的结构更改为:
super(subcontfig,self)。\uuuuuuuu setattr\uuuuuuuu(“\uuuu config”,config)
。这样,我覆盖的
\uuuuu setattr\uuuuu
就不起作用了。此外,我还可以在setter中添加一些if来传递以双下划线开头的值。
setattr
不起作用,因为它总是遇到
\uuuuuuuuuuuuuuuuuuuu
机器。请参阅上面添加的代码。感谢您的建议,解决方案是将所有设置器的结构更改为:
super(subcontfig,self)。\uuuuuuuu setattr\uuuuuuuuu(“\uuuuu config',config)
。这样,我覆盖的
\uuuuu setattr\uuuuu
就不起作用了。此外,我还可以在setter中添加一些if来传递以双下划线开头的值。
setattr
不起作用,因为它总是遇到
\uuuuuuuuuuuuuuuuuuuu
机器。请参阅上面添加的代码。