pythonclass

How to dynamically define class variables?


Let's say I want to create a class:

class Foo:
    hello = "world"
    goodbye = "moon"

But both of those class variables are dynamically provided.

attrs = [("hello", "world"), ("goodbye", "moon")]


def create_class(attrs):

    class Foo:
        # INSERT DYNAMIC ATTRS HERE
        pass


create_class(attrs)

How can I dynamically set those attributes as class variables at the time the class is defined? I know I can use setattr to set them after the class is created, but this is not what I'm looking for.

I'm thinking this is possible with __build_class__ but I'm struggling to implement it myself.


Solution

  • You can do this by using the type function. It looks like this....

    attrs = [("hello", "world"), ("goodbye", "moon")]
    
    def create_class(attrs):
        # Create a dictionary of the attributes
        attr_dict = dict(attrs)
        
        # Use the type function to create the class dynamically
        Foo = type('Foo', (object,), attr_dict)
        
        return Foo
    
    # Create the class
    my_class = create_class(attrs)
    
    # Check the attributes
    print(my_class.hello)    # Output: world
    print(my_class.goodbye)  # Output: moon
    

    If you want to inherit then you just pass that to the types arg in the second tuple.

    # Define a base class
    class BaseClass:
        base_attr = "base"
    
        def base_method(self):
            return "This is a method from BaseClass"
    
    # Attributes to be added to the new class
    attrs = [("hello", "world"), ("goodbye", "moon")]
    
    def create_class(attrs, base_classes):
        # Create a dictionary of the attributes
        attr_dict = dict(attrs)
        
        # Use the type function to create the class dynamically with inheritance
        Foo = type('Foo', base_classes, attr_dict)
        
        return Foo
    
    # Create the class, inheriting from BaseClass
    my_class = create_class(attrs, (BaseClass,))
    
    # Check the attributes
    print(my_class.hello)    # Output: world
    print(my_class.goodbye)  # Output: moon
    
    # Check inherited attributes and methods
    print(my_class.base_attr)               # Output: base
    print(my_class().base_method())         # Output: This is a method