【问题标题】:Create class with properties from config file使用配置文件中的属性创建类
【发布时间】:2022-01-01 16:47:46
【问题描述】:

我正在尝试从配置文件动态创建 Python 类(为简单起见,我在示例中使用字典)。我希望将我创建的属性设置为属性,因为我有验证功能,我想在设置属性时运行这些功能。

我有一个可以正常工作的代码,但它产生了一些意想不到的结果。

def func(x):
    """ Example validation function. """
    if x < 0:
        raise ValueError

    return


config = {
    "x": {
        "type": int,
        "default": 0,
        "validate": func
    },
    "y": {
        "type": int,
        "default": 10,
        "validate": func
    },
    "z": {
        "type": str,
        "default": "bar",
        "validate": None
    }
}


def get_property(prop, validate):
    key = f"_{prop}"

    def get_(self):
        return exec(f"self.{key}")

    def set_(self, value):
        if validate is not None:
            validate(value)
        exec(f"self.{key} = value")

    def del_(self):
        exec(f"del self.{key}")

    return property(get_, set_, del_)


def get_Foo(**kwargs):
    class Foo:
        def __init__(self, **_kwargs):
            for k_, v_ in _kwargs.items():
                setattr(self, "_" + k_, None)

                if v_["type"] == str:
                    exec(f"self.{k_} = '{v_['default']}'")
                else:
                    exec(f"self.{k_} = {v_['default']}")

    # Add properties to Foo class
    for k, v in kwargs.items():
        prop_ = get_property(k, v["validate"])
        setattr(Foo, k, prop_)

    # Create Foo class and set defaults
    return Foo(**kwargs)


foo = get_Foo(**config)

现在,在测试时,“setter”似乎正在工作,但“getter”却没有,“deleter”正在部分工作。

print(foo.x)  # prints None
print(foo._x) # prints 0
foo.x = 10
print(foo.x)  # prints None (getter not working)
print(foo._x) # prints 10  (setter works)
foo.x = -1    # raises error (validator in setter works)
del foo.x
print(foo.x)  # AttributeError: 'Foo' object has no attribute '_x' (del sort-of works?)

谁能解释一下结果?

【问题讨论】:

  • exec(f"self.{key}") 不要那样做!
  • exec 总是返回None。你需要使用eval,但你不应该使用或者,所有这些都使用getattrsetattr,以及delattr\

标签: python class properties


【解决方案1】:

感谢 juanpa.arrivillaga;切换到 getattr、setattr、delattr 解决了这个问题。

解决办法如下:

def get_property(prop, validate):
    key = f"_{prop}"

    def get_(self):
        return getattr(self, key)

    def set_(self, value):
        if validate is not None:
            validate(value)
        setattr(self, key, value)

    def del_(self):
        delattr(self, key)

    return property(get_, set_, del_)


def get_Foo(**kwargs):
    class Foo:
        def __init__(self, **_kwargs):
            for k_, v_ in _kwargs.items():
                setattr(self, "_" + k_, None)
                setattr(self, k_, v_['default'])

    # Add properties to Foo class
    for k, v in kwargs.items():
        prop_ = get_property(k, v["validate"])
        setattr(Foo, k, prop_)

    # Create Foo class and set defaults
    return Foo(**kwargs)


foo = get_Foo(**config)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-07
    • 2012-05-09
    相关资源
    最近更新 更多