Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python decorator to add class-level variables

I have 2 classes A and B:

class A(object):
    x = 0

class B(object):
    y = 0

How can I make it so B "inherits" A's class-level variables (x in this case) by using decorators? Is it at all possible? The desired behavior (if possible), after decorated, B would look like this:

class B(object):
    x = 0
    y = 0

Note: If anyone wants/needs to know why I'm asking this, it's simply to make SQLAlchemy's Concrete Table Inheritance look nicer in code, although I can see many use cases for such behavior.

like image 740
stelonix Avatar asked Aug 18 '12 00:08

stelonix


1 Answers

Sure you can; you can use a class decorator that takes class A as an argument, then updates the decorated class for you:

import types

class copyattributes(object):
    def __init__(self, source):
        self.source = source

    def __call__(self, target):
        for attr, value in self.source.__dict__.items():
            if attr.startswith('__'):
                continue
            if isinstance(value, (property, types.FunctionType)):
                continue
            setattr(target, attr, value)
        return target

The decorator copies anything that is really an attribute (not a function or a property), and doesn't start with a double underscore.

Usage:

class A(object):
    x = 0

@copyattributes(A)
class B(object):
    y = 0

Tested on the prompt:

>>> class A(object):
...     x = 0
...
>>> @copyattributes(A)
... class B(object):
...     y = 0
... 
>>> B.y
0
>>> B.x
0
>>> dir(B)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'x', 'y']
like image 121
Martijn Pieters Avatar answered Sep 28 '22 05:09

Martijn Pieters