首页 > 解决方案 > 是否有一种紧凑的方法可以在 python 类中声明几个类似的属性?

问题描述

我正在一个更大的python模块中工作,其中可以保存包含类dict类实例程序集的“项目”,但是为了保存类的属性,它们必须存储在类中的特定字典中。通过将属性写为属性,我可以将属性作为简单属性(self.x而不是self.properties['x'])进行访问。但是我最多有 9 个这样的东西,给它们每个都一个 getter、setter 和 deleter 似乎是在浪费空间,尤其是因为它们都那么微不足道。有没有更好的办法?

太长:

class MyClass(dict):

    @property
    def variable1(self):
        return self.properties.get('variable1', None)

    @variable1.setter
    def variable1(self, value):
        self.properties['variable1'] = value

    @variable1.deleter
    def variable1(self):
        self.properties['variable1'] = None

    # ... same for variables 2 - 8, so boring

    @property
    def variable9(self):
        return self.properties.get('variable9', None)

    @variable9.setter
    def variable9(self, value):
        self.properties['variable9'] = value

    @variable9.deleter
    def variable9(self):
        self.properties['variable9'] = None

    def __init__(self, variable1='default1', variable9='default9'):
        self.properties = dict(variable1=variable1, variable9=variable9)
        dict.__init__(self)

我怎样才能循环属性声明,这样会更短?

奖励:如果我做一个循环,有没有办法在需要时对某些变量进行小幅定制(也许将要列出的东西声明为字典中的键,其中值是小定制的说明)?

上面例子的测试/使用:

from var_test import MyClass  # If you saved it in var_test.py
a = MyClass(variable1=1234)
b = MyClass(variable1='wheee')
assert a.variable1 is not b.variable1
assert a.properties['variable1'] == a.variable1
assert a.variable1 == 1234

标签: pythonproperties

解决方案


是的,您可以动态创建属性对象,并将它们添加到类中:

def gen_property(name):
    def getter(self):
        return self.properties.get(name, None)
    def setter(self, value):
        self.properties[name] = value
    def deleter(self):
        self.properties[name] = None

    return property(getter, setter, deleter)

class MyClass(dict):
    def __init__(self, variable1='default1', variable9='default9'):
        self.properties = dict(variable1=variable1, variable9=variable9)
        dict.__init__(self)

for number in range(1, 10):
    name = 'variable{}'.format(number)
    setattr(MyClass, name, gen_property(name))

但是,使用属性访问自定义钩子并将属性名称代理到self.properties那里的字典可能要干净得多:

class MyClass(dict):
    def __init__(self, variable1='default1', variable9='default9'):
        self.properties = dict(variable1=variable1, variable9=variable9)
        dict.__init__(self)

    def __getattr__(self, name):
        if name.startswith('variable') and name[8:].isdigit():
            return self.properties.get(name, None)
        raise AttributeError(name)

    def __setattr__(self, name, value):
        if name.startswith('variable') and name[8:].isdigit():
            self.properties[name] = value
            return
        super().__setattr__(name, value)

    def __delattr__(self, name):
        if name.startswith('variable') and name[8:].isdigit():
            self.properties[name] = None
            return
        super().__delattr__(name)

推荐阅读