在Python中通过装饰器动态添加实例变量到类中

1 投票
3 回答
1922 浏览
提问于 2025-04-16 01:24

我想通过装饰器来给一个类添加一些实例变量,这些变量是由类的作者指定的。

我开始写了以下代码,但这段代码只添加了变量,而我想要的是实例变量(通常是在__ init __中“声明”的变量)。

有什么更符合Python风格的方法可以做到这一点,同时又能让类的作者控制他们在__ init __中放入什么?

def add_list_attributes(klass):
    for attribute in klass.list_attributes:
        setattr(klass, attribute, [])

    return klass

@add_list_attributes
class Person(object):

    list_attributes = [
        'phone_numbers'
    ]

    def __init__(self):
        pass

p1 = Person()
p1.phone_numbers.append('01234')

print p1.phone_numbers

3 个回答

2

你可以通过包裹(也就是在外面加一层)__init__ 方法来实现你的需求,然后再调用原来的 __init__ 方法:

def add_list_attributes(klass):
    old_init = klass.__init__
    def new_init(self, *args, **kwargs):
        for attribute in klass.list_attributes:
            setattr(self, attribute, [])
        old_init(self, *args, **kwargs)
    klass.__init__ = new_init
    return klass

@add_list_attributes
class Person(object):

    list_attributes = [
        'phone_numbers'
    ]

    def __init__(self):
        pass

p1 = Person()
p1.phone_numbers.append('01234')
p2 = Person()
p2.phone_numbers.append('56789')

print p1.phone_numbers
print p2.phone_numbers
2

你需要把 __init__() 放在一个单独的函数里,这个函数会先调用原来的方法,然后再给第一个参数添加你自己的属性。

2

你可以创建一个自定义的 __new__ 方法:

def add_list_attributes(klass):
    def new(cls, *args, **kwargs):
        result = super(cls, cls).__new__(cls)
        for attribute in klass.list_attributes:
            setattr(result, attribute, [])
        return result
    klass.__new__ = staticmethod(new)
    return klass

@add_list_attributes
class Person(object):
    list_attributes = [
        'phone_numbers'
    ]
    def __init__(self):
        pass

p1 = Person()
p2 = Person()
p1.phone_numbers.append('01234')

print p1.phone_numbers, p2.phone_numbers

撰写回答