Search code examples
list-comprehensionargsmanim

Use of *args in manim ReplacementTransform animation


I have a question regarding this piece of code, which transforms the elements of TexMobject (for example, element 2 is transformed to 8, 3 is transformed to 9 and so on):

changes = [
          [(2,4,3), (8,11,9)],
          [(0,0), (7,10)]
          ]    

for pre_ind, post_ind in changes:
        self.play(
            *[
                ReplacementTransform(formula[i].copy(), formula[j])
                for i,j in zip(pre_ind, post_ind)
            ]
        )
        self.wait()
    self.wait()

I see that there is a list comprehension used to generate indices pairs, but I don't understand why is there an args asterisk (*) before the square brackets in self.play()? What is the purpose of using *args notation in this case, if list comprehension works without it?


Solution

  • You have to understand a couple of concepts before:

    1. List comprehension only works on lists, tuples, dictionaries and sets.
    2. self.play() refers to Scene.play(), because we know that self refers to the class being defined.
    3. ALL METHODS have the following form: class.method(*args,**kwargs), or
    class.method(*args_1, *args_2, *args_3, ..., *args_n,**kwargs_1, **kwargs_2, ..., **kwargs_m)
    

    Where args is a LIST/TUPLA and kwargs is a dictionary. In this case, Scene.play is used like this:

    Scene.play(Animation1(...), Animation2(...), ..., **kwargs)
    # Example:
    Scene.play(Write(mob1), Write(mob2), run_time=4)
    
    # But, this is the same as:
    Scene.play(*[Write(mob1), Write(mob2)], run_time=4)
    
    # Or better:
    Scene.play(*[Write(mobs) for mobs in [mob1,mob2]], run_time=4)
    

    I suppose (you didn't make it very clear) that you are referring to why you can't do something like:

    Scene.play([ReplacementTransform(...) for _ in ...])
    

    or

    Scene.play(ReplacementTransform(...) for _ in ...)
    

    Intuitively we can understand that this is a syntax error, because the Python interpreter will not be able to understand the parameters that are being given, remember that this is NOT the way to use a method.

    The operator * is called "spread operator", what it does is "take out" all the elements that are in a list. More information here.