How to implement an "Apply" behavior in python

Question:

I’d like to implement an apply() behavior in a class instance.

by "Apply" i mean, typically realizing a parametric object in place. Meaning that the user might create a parametric object, change it’s settings, and later on, realize the object.

Here is an example on how such an apply behavior would work in the context of a 3D application


my_cube = ParametricCube()
my_cube.height = 2
my_cube.width = 1
my_cube.subdivision = 3

print(type(my_cube),) 
>>> <class ParametricCube>

#.. a few moments later

my_cube.make_real() #== apply in place behavior!

print(type(my_cube),) 
>>> <class 3D_Object>

The pythonic way to do it, would be to re-assign the variable
instead of using my_cube.make_real() we would use my_cube = my_cube.make_real()
i am not interested by this solution, we’d like to directly impact the value of my_cube w/o monkey patching many variable severywhere at runtime

Here is an abstract example, un-related to an 3D app context

class Expression():
    """parametric expression of a+b+c"""

    def __init__(self):
        #parameters defaults
        self.a = 1
        self.b = 2
        self.c = 3

    def __str__(self):
        return str(f"<Expression '{self.a}+{self.b}+{self.c}'={self.a + self.b + self.c}>")

    def realize(self):
        """apply in place behavior"""

        #realize our expression into an int or float somehow?

        return None

x = Expression()
x.a = 1
x.b = 1
x.c = 1

print(x) 
>>>"<Expression 1+1+1=3>"

print(type(x))
>>> <class Expression>

#apply in place behavior
x.realize()

print(x) 
>>>3

print(type(x))
>>> <class 'float'>

Asked By: DB3D

||

Answers:

I’m not sure what are you asking for, but what about this?

class Realized:
    def __str__(self):
        return str(self.a + self.b + self.c)


class Expression:
    """a+b+c parametric expression"""

    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3

    def __str__(self):
        return str(
            f"<Expression '{self.a}+{self.b}+{self.c}'={self.a + self.b + self.c}>"
        )

    def realize(self):
        """apply in place behavior"""

        # how to apply self into ??
        temp = self
        self.__class__ = Realized  # Change the type of the object
        self.__dict__.update(temp.__dict__)  # Copy over data

        return None


x = Expression()
x.a = 1
x.b = 1
x.c = 1

print(x)

print(type(x))

x.realize()  # apply in place behavior

print(x)
print(type(x))

Output:

$ python test.py

<Expression '1+1+1'=3>
<class '__main__.Expression'>
3
<class '__main__.Realized'>

Here’s an extendable implementation:

from typing import Any


class Realizable:
    """Inherit this to have a class that can be realized"""

    """Private var to hold class type to be realized"""
    _realize_class_type: Any

    def __init__(self, *args, **kwargs):
        self._realize_class_type = kwargs["realizer"]

    def realize(self):
        """apply in place behavior"""

        temp = self
        self.__class__ = self._realize_class_type  # Change the type of the object
        self.__dict__.update(temp.__dict__)  # Copy over data


class ExpressionRealized:
    def __str__(self):
        return str(self.a + self.b + self.c)


class Expression(Realizable):
    """a+b+c parametric expression"""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.a = 1
        self.b = 2
        self.c = 3

    def __str__(self):
        return str(
            f"<Expression '{self.a}+{self.b}+{self.c}'={self.a + self.b + self.c}>"
        )


x = Expression(realizer=ExpressionRealized)
x.a = 1
x.b = 1
x.c = 1

print(x)

print(type(x))

x.realize()  # apply in place behavior

print(x)
print(type(x))
Answered By: Lim Meng Kiat
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.