Caio Filus
Caio Filus

Reputation: 714

How to define a class with dynamic attributes?

In my project, I need to create a class with attributes passed by a dict, something like this:

class_attributes = {"sensor": Nested(Sensor),
                    "serial_interface": Nested(SerialInterface)}
class MSchema(marshmallow.ModelSchema):
    class Meta:
        model = cls

    attr = class_attributes

I need that "sensor" and "serial_interface" to be in the class, and can be access using MSchema.sensor or MSchema.serial_interface.

Upvotes: 0

Views: 183

Answers (2)

chepner
chepner

Reputation: 530823

You can call the metaclass of ModelSchema directly, rather than defining the class declaratively using a class statement.

m = marshmallow.ModelSchema

class_attributes = {
    "sensor": Nested(Sensor),
    "serial_interface": Nested(SerialInterface)
}

m = marshmallow.ModelSchema
mc = type(m)
MSchema = mc('MSchema', (m,), {
    'Meta': type('Meta', (), {'model': cls}),
    **class_attributes
    })

In case you aren't aware, a class statement is just a declarative syntax for calling type (or some other metaclass) with 3 arguments: the name of the class, a tuple of parent classes, and a dict of class attributes. The class statement evaluates its body to produce the dict, then calls type (or another given metaclass), and binds the return value to the name. Some simpler examples:

 # Foo = type('Foo', (), {})
 class Foo:
     pass

 # Foo = Bar('Foo', (), {})
 class Foo(metaclass=Bar):
     pass

 # Foo = Bar('Foo', (Parent,), {'x': 3})
 class Foo(Parent, metaclass=Bar):
     x = 3

 # def foo_init(self, x):
 #     self.x = x 
 # Foo = Bar('Foo', (), {'__init__': foo_init})
 class Foo(metaclass=Bar):
     def __init__(self, x):
         self.x = x

Upvotes: 3

AMargheriti
AMargheriti

Reputation: 313

Not entirely sure I understand the question to 100%, but have you tried using setattr()?

Example code would look like the following:

m_schema = MSchema()
for key, value in class_attributes.items():
    setattr(m_schema, key, value)

setattr(object, string, value) takes an object to set attributes on, a string for the attribute name, and an arbitrary value as the attribute value.

Upvotes: 0

Related Questions