如何为动态添加的属性定义setter,getter

时间:2019-06-04 05:36:37

标签: python

我的课程如下:

class A:
    def __init__(self):
        pass

    def add_attr(self, name):
        setattr(self, name, 'something')

如何为self.name定义自定义二传手,getter?我不能使用__setattr____getattribute__,因为这也会改变add_attr的行为。

编辑:此类的用户将添加具有任意名称的任意数量的属性:

a = A()
a.add_attr('attr1')
a.add_attr('attr2')

我只希望对这些用户添加的属性进行自定义行为。

4 个答案:

答案 0 :(得分:2)

以@Devesh Kumar Singh的答案为基础,我将以这种方式实现它:

class A:
    def __init__(self):
        self.attrs = {}

    def __setattr__(self, key, value):
        if key in self.attrs:
            self.set_attr(key, value)
        else:
            object.__setattr__(self, key, value)

    def __getattribute__(self, key):
         if key in self.__dict__.get(attrs, {}):
             return self.__dict__['get_attr'](self, key)
         return object.__getattribute__(self, key)

    def get_attr(self, key):
        r = self.attrs[key]
        # logic
        return r

    def set_attr(self, key, value):
        # logic
        self.attrs[key] = value

    def add_attr(self, key, value=None):
        self.attrs[key] = value 

add_attr仅用于首次初始化变量。您还可以编辑__setattr__来设置self.attrs中的所有新属性,而不是self.__dict__

答案 1 :(得分:1)

我想到的一种可能性是拥有一个动态属性字典,并使用该字典设置和获取动态属性

class A:
    def __init__(self):
        #Dictionary of attributes
        self.attrs = {}

    #Set attribute
    def set_attr(self, name):
        self.attrs[name] = 'something'

    #Get attribute
    def get_attr(self, name):
        return self.attrs.get(name)

a = A()
a.set_attr('var')
print(a.get_attr('var'))

输出将为something

或者替代方法是使用property装饰器在类外部显式添加参数,如here

所述
class A:
    def __init__(self):
        pass

a = A()
#Add attributes via property decorator
a.attr_1 = property(lambda self: self.attr_1)
a.attr_2 = property(lambda self: self.attr_2)

#Assign them values and print them
a.attr_1 = 4
a.attr_2 = 6

print(a.attr_1, a.attr_2)

输出将为4 6

答案 2 :(得分:1)

自定义getter和setter逻辑?这就是property的用途。通常,这些用于魔术屏蔽函数调用,并使它们看起来像属性访问

class MyDoubler(object):
    def __init__(self, x):
        self._x = x

    @property
    def x(self):
        return x * 2

    @x.setter
    def x(self, value):
        self._x = value

>>> md = MyDoubler(10)
>>> md.x
20
>>> md.x = 20
>>> md.x
40
>>> md._x
20

但是没有规则说您不能滥用该功能为自定义器和自定义器添加自定义行为。

class A(object):
    def __init__(self):
        pass

    @staticmethod
    def default_getter_factory(name):
        def default_getter(self):
            return self.name
        return default_getter

    @staticmethod
    def default_setter_factory(name):
        def default_setter(self, value):
            setattr(self, name, value)
        return default_setter

    def add_attr(self, name, getterfactory=None, setterfactory=None):
        private_name = f"_{name}"

        if getterfactory is None:
            getterfactory = self.__class__.default_getter_factory
        if setterfactory is None:
            setterfactory = self.__class__.default_setter_factory

        getter, setter = getterfactory(private_name), setterfactory(private_name)

        getter = property(getter)
        setattr(self.__class__, name, getter)
        setattr(self.__class__, name, getter.setter(setter))

这说起来有点愚蠢,而且很可能您试图做的事情都是不应该做的。动态编程是件好事,但是如果我要回顾做到这一点的代码,那么在批准其他解决方案之前,我会思考很长时间并且很难。这对我来说有点技术债务。

答案 3 :(得分:1)

我将回答自己的问题,仅供参考。这是基于此处其他人的答案。想法是对未通过__setattr__添加的属性使用默认的__getattribute__add_attr

class A:
    def __init__(self):
        self.attrs = {}

    def add_attr(self, name):
        self.attrs[name] = 'something'

    def __getattribute__(self, name):
        try:
            object.__getattribute__(self, 'attrs')[name]  # valid only if added by user
            # custom logic and return 
        except (KeyError, AttributeError):
           return object.__getattribute__(self, name)

    def __setattr__(self, name, val):
        # similar to __getattribute__