Repository: ManimCommunity/manim
Pull request: Make VGroup and VDict printable
Closes #497 
## List of Changes
- Added a `__repr__` method to `VGroup` and `VDict`
- Removed the `__str__` method from `Mobject` (reason explained below)

## Motivation
Just printing a VGroup or a VDict object used to print the class name only. While debugging, it is useful to know the mobjects contained. With this change, something like this is printed:
```text
VGroup(<manim.mobject.geometry.Square object at 0x00000265DAC2B610>, <manim.mobject.geometry.Circle object at 0x00000265EA936850>)
VDict({'s': <manim.mobject.geometry.Square object at 0x00000265DAC2B610>, 'c': <manim.mobject.geometry.Circle object at 0x00000265EA936850>})
```
which, I believe is more useful

## Explanation for Changes
I know the long output looks a bit ugly, but hopefully, in a separate PR, we would love to implement `__repr__` for mobjects as [suggested](https://github.com/ManimCommunity/manim/issues/497#issuecomment-702016103) by @behackl.
I had to remove the `__str__` for `Mobject` because for it `__repr__` isn't defined yet. So all the inheriting classes are using `__str__` which is what we don't want.
## Acknowledgement
- [ ] I have read the [Contributing Guidelines](https://github.com/ManimCommunity/manim/wiki/Documentation-guidelines-(WIP))




Problem statement:
VGroup and VDict must override __repr__ to display the mobjects contained
Consider this example:
```python
class Test(Scene):
    def construct(self):
        sq = Square()
        cir = Circle()
        grp = VGroup(sq, cir)
        print(grp) # --> Just prints: VGroup
        self.play(ShowCreation(grp))
        dct = VDict({'s' : sq, 'c' : cir}).next_to(grp, DOWN)
        print(dct) # --> Just prints: VDict
        self.play(ShowCreation(dct))
```
When there are _a lot_ of mobjects in the `VGroup` or `VDict`, it sometimes helps to know what are those mobjects while debugging.
Something like
`[Square, Circle]` or even better the full hash name (IDK what it's called) -- `manim.mobject....at 0x00...`.
Let me know how can this be best incorporated.

Hints from issue discussion:
You have to define the `__str__` method of VGriup/VDict. I think some Mobjects already have a `__str__` method so it should be enough to do something like `return ", ".join(str(m) for m in self.mobjects)`
Seems to be an easy PR, if no one object 
Would like to know what would be preferred just `Square` or the full hash name? I can make a quick PR today if no one minds.
I would prefer implementing `__repr__` over `__str__` (see https://stackoverflow.com/questions/1436703/difference-between-str-and-repr), and would love to see more manim classes having proper `__repr__` methods. (Note in particular: if `__repr__` is defined and `__str__` is not, `str(object)` will still work.)

For the container, I fully agree that its repr should print a list of its children. But for something concrete like `Square` I would find it useful to let `Square(side_length=5)` print something like `'Square with side length 5'`, or even `'Square with side length 5 and center (0., 0., 0.)'`; the more explicit and defining the better. (For your PR it is fine to just take care of `VGroup` and `VDict`, improving their representation strings is definitely more important. 👍)
> Would like to know what would be preferred just `Square` or the full hash name? I can make a quick PR today if no one minds.

What hash ? 
> What hash ?

This
`<manim.mobject.geometry.Square object at 0x000001AA9A5E7790>`
I am not sure what's the proper name for this - I call this "printing the object"
I don't know the proper name either lol, but the hex thing at the end is the id, I think. 
And I think the id in the repr _can_ be sometimes useful, when one wants to check if two objects are different.

Commit message: Add change to changelog.rst

Patch to review:
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
index 85fdd00ce3..b478a9ff76 100644
--- a/docs/source/changelog.rst
+++ b/docs/source/changelog.rst
@@ -60,7 +60,7 @@ Mobjects, Scenes, and Animations
 #. The :code:`Container` class has been made into an AbstractBaseClass, i.e. in cannot be instantiated.  Instead, use one of its children classes
 #. The ``TextMobject`` and ``TexMobject`` objects have been deprecated, due to their confusing names, in favour of ``Tex`` and ``MathTex``. You can still, however, continue to use ``TextMobject`` and ``TexMobject``, albeit with Deprecation Warnings constantly reminding you to switch.
 #. Add a :code:`Variable` class for displaying text that continuously updates to reflect the value of a python variable.
-
+#. :code:`VGroup` and :code:`VDict` now support printing the contained mobjects.
 
 
 Documentation
diff --git a/manim/mobject/mobject.py b/manim/mobject/mobject.py
index 3b6f6e6e50..0d7244a5a2 100644
--- a/manim/mobject/mobject.py
+++ b/manim/mobject/mobject.py
@@ -62,9 +62,6 @@ def __init__(self, **kwargs):
         self.generate_points()
         self.init_colors()
 
-    def __str__(self):
-        return str(self.name)
-
     def reset_points(self):
         self.points = np.zeros((0, self.dim))
 
diff --git a/manim/mobject/types/vectorized_mobject.py b/manim/mobject/types/vectorized_mobject.py
index cbc63d9c85..4f3d6eef7e 100644
--- a/manim/mobject/types/vectorized_mobject.py
+++ b/manim/mobject/types/vectorized_mobject.py
@@ -876,6 +876,14 @@ def __init__(self, *vmobjects, **kwargs):
         VMobject.__init__(self, **kwargs)
         self.add(*vmobjects)
 
+    def __repr__(self):
+        return (
+            __class__.__name__
+            + "("
+            + ", ".join(str(mob) for mob in self.submobjects)
+            + ")"
+        )
+
     def add(self, *vmobjects):
         """Checks if all passed elements are an instance of VMobject and then add them to submobjects
 
@@ -934,6 +942,9 @@ def __init__(self, mapping_or_iterable={}, show_keys=False, **kwargs):
         self.submob_dict = {}
         self.add(mapping_or_iterable)
 
+    def __repr__(self):
+        return __class__.__name__ + "(" + repr(self.submob_dict) + ")"
+
     def add(self, mapping_or_iterable):
         """Adds the key-value pairs to the :class:`VDict` object.
 


Code review comments:
diff_hunk: @@ -62,9 +62,6 @@ def __init__(self, **kwargs):
         self.generate_points()
         self.init_colors()
 
-    def __str__(self):
path: manim/mobject/mobject.py
text: @user1:
Question: Why are we removing this? It doesn't seem to help this issue (which is about VGroup and VDict).

@author:
If by keeping this, you do a `print(grp)`, you'll get the same old output of `VGroup` because when both str and repr are defined and you do a `print(grp)` (as opposed to a `repr(grp)`) it uses the `__str__` method. For VGroup and VDict, the str method is inherited from Mobject and hence we remove it from the Mobject itself.
One might ask, "Why not use repr(grp) for printing the VGroup?" I think print is more common and more people are more likely to use it as first instinct.

@user1:
Ok I see. I'd suggest implementing this as `Mobject.__repr__` instead of deleting it. In this way, all mobjects will still have a string representation, and your other changes will make it so that `VGroup.__repr__` overrides `Mobject.__repr__`.

@author:
I thought we would be implementing __repr__ for Mobjects in a separate PR, no? Since for a Mobject, there isn't anything specific you can print. Like for a Square, it would be "Square with side length = 2" but for circle it would be "Circle with radius 2". That being said, still feel free to suggest what could possibly go in Mojects's repr.

@user1:
Even if we do take care of that in another PR, this PR shouldn't leave all mobjects without a str/repr method.

@user1:
Just copy the current `__str__` into a `__repr__` for now.

@author:
Yes, that's a good solution.

diff_hunk: @@ -876,6 +876,14 @@ def __init__(self, *vmobjects, **kwargs):
         VMobject.__init__(self, **kwargs)
         self.add(*vmobjects)
 
+    def __repr__(self):
+        return (
+            __class__.__name__
path: manim/mobject/types/vectorized_mobject.py
text: @user1:
shouldn't this be `self.__class__`?

@author:
I just checked. Either of them gives the same output. I guess it's better to go with `self` then.