Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I add properties to a class using a decorator that takes a list of names as argument?

I would like to add many dummy-properties to a class via a decorator, like this:

def addAttrs(attr_names):
  def deco(cls):
    for attr_name in attr_names:
      def getAttr(self):
        return getattr(self, "_" + attr_name)
      def setAttr(self, value):
        setattr(self, "_" + attr_name, value)
      prop = property(getAttr, setAttr)
      setattr(cls, attr_name, prop)
      setattr(cls, "_" + attr_name, None) # Default value for that attribute
    return cls
  return deco

@addAttrs(['x', 'y'])
class MyClass(object):
  pass

Unfortunately, the decoarator seems to keep the reference of attr_name instead of its content. Therefore, MyClass.x and MyClass.y access both MyClass._y:

a = MyClass()
a.x = 5
print a._x, a._y
>>> None, 5
a.y = 8
print a._x, a._y
>>> None, 8

What do I have to change to get the expected behavior?

like image 477
Philipp der Rautenberg Avatar asked Feb 03 '12 08:02

Philipp der Rautenberg


People also ask

Can you use a decorator on a class?

To provide data input integrity, a decorator can be used to decorate a method defined in the class.

Which decorator function is used to create a class method?

We use @classmethod decorator in python to create a class method and we use @staticmethod decorator to create a static method in python.

How do you add a class to a decorator in Python?

To decorate a function with a class, we must use the @syntax followed by our class name above the function definition. Following convention, we will use camel-case for our class name. In the class definition, we define two methods: the init constructor and the magic (or dunder) call method.

How do you use the class method decorator?

In Python, the @classmethod decorator is used to declare a method in the class as a class method that can be called using ClassName. MethodName() . The class method can also be called using an object of the class. The @classmethod is an alternative of the classmethod() function.

What is the use of property decorator in Python?

The @property is a built-in decorator for the property() function in Python. It is used to give "special" functionality to certain methods to make them act as getters, setters, or deleters when we define properties in a class.


1 Answers

You almost had it working. There is just one nit. When creating the inner functions, bind the current value of attr_name into the getter and setter functions:

def addAttrs(attr_names):
  def deco(cls):
    for attr_name in attr_names:
      def getAttr(self, attr_name=attr_name):
        return getattr(self, "_" + attr_name)
      def setAttr(self, value, attr_name=attr_name):
        setattr(self, "_" + attr_name, value)
      prop = property(getAttr, setAttr)
      setattr(cls, attr_name, prop)
      setattr(cls, "_" + attr_name, None) # Default value for that attribute
    return cls
  return deco

@addAttrs(['x', 'y'])
class MyClass(object):
  pass

This produces the expected result:

>>> a = MyClass()
>>> a.x = 5
>>> print a._x, a._y
5 None
>>> a.y = 8
>>> print a._x, a._y
5 8

Hope this helps. Happy decorating :-)

like image 70
Raymond Hettinger Avatar answered Nov 14 '22 22:11

Raymond Hettinger