Skip to content

Define __repr__, not __str__ for transforms. #11173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

anntzer
Copy link
Contributor

@anntzer anntzer commented May 5, 2018

str falls back on repr (but not the other way round), so def __repr__(self): return str(self) was causing a recursion error.
Defining __repr__ directly side-steps the issue.

(https://docs.python.org/3/reference/datamodel.html#object.__str__, e.g.

In [1]: class T:
   ...:     def __repr__(self): return "4242"
   ...: 
   ...: 

In [2]: str(T())
Out[2]: '4242'

In [3]: repr(T())
Out[3]: '4242'

In [4]: class T:
   ...:     def __str__(self): return "4242"
   ...: 
   ...: 

In [5]: str(T())
Out[5]: '4242'

In [6]: repr(T())
Out[6]: '<__main__.T object at 0x7fb33f6e88d0>'

)

Supersedes #11171; closes #11163.

PR Summary

PR Checklist

  • Has Pytest style unit tests
  • Code is PEP 8 compliant
  • New features are documented, with examples if plot related
  • Documentation is sphinx and numpydoc compliant
  • Added an entry to doc/users/next_whats_new/ if major new feature (follow instructions in README.rst there)
  • Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way

@anntzer anntzer added this to the v2.2.3 milestone May 5, 2018
str falls back on repr (but not the other way round), so `def
__repr__(self): return str(self)` was causing a recursion error.
Defining `__repr__` directly side-steps the issue.
@timhoffm
Copy link
Member

timhoffm commented May 5, 2018

Not sure, it's actually good to have that verbose reprs. On the other hand, someone had decided to have them by pulling in the str. So it's probably ok and at least not a change to the previous behavior..

@jklymak
Copy link
Member

jklymak commented May 5, 2018

OK, my quick study of this was that __repr__ is supposed to be the basic unambiguous representation of the object, and __str__ is supposed to be the user-facing object. So a __repr__ that returns __str__ is backwards, and we shouldn't have had that.

https://stackoverflow.com/questions/1436703/difference-between-str-and-repr

OTOH, I think I agree w/ @timhoffm that it seems strange to have such a verbose __repr__, and just have __str__ fall back on that. It seems that __repr__ should be a short unique identifier of the transform and __str__ should be the user-facing representation w/ all the indenting and representation of the matrices. But I'm not an expert on this. Just throwing it out there for discussion.

@ImportanceOfBeingErnest
Copy link
Member

My personal two bits on this: I like the verbosity when doing print(transform) and it can be really helpful for debugging. It's also much easier to shorten the long form into a single line if needed than vice versa.
If other people have really strong objections, maybe there is another way to make the long form available?

@jklymak
Copy link
Member

jklymak commented May 5, 2018

Print will use the str form. I’m totally for the str form as the verbose version we have.

@ImportanceOfBeingErnest
Copy link
Member

Ah, ok, so in which case would the __repr__ used then? What happens if you type artist.get_transform() + Enter in IPython, is this the __str__ as well?

@jklymak
Copy link
Member

jklymak commented May 5, 2018

90% sure thats the __repr__

@timhoffm
Copy link
Member

timhoffm commented May 5, 2018

Maybe we should just remove the __repr__ and let python use its default?

When is is used?

  • ipython outputs and printing list elements use repr (probably because it's considered to be shorter than str).
  • print() uses str.

as can seen in the following example which has the __repr__ deleted.

In [14]: ax.transAxes
Out[14]: <matplotlib.transforms.BboxTransformTo at 0x7f5dacff9ac8>

In [15]: print(ax.transAxes)
BboxTransformTo(
    TransformedBbox(
        Bbox(x0=0.125, y0=0.10999999999999999, x1=0.9, y1=0.88),
        BboxTransformTo(
            TransformedBbox(
                Bbox(x0=0.0, y0=0.0, x1=5.5, y1=4.5),
                Affine2D(
                    [[100.   0.   0.]
                     [  0. 100.   0.]
                     [  0.   0.   1.]])))))

In [16]: l = [ax.transAxes]

In [17]: print(l)
[<matplotlib.transforms.BboxTransformTo object at 0x7f5dacff9ac8>]

If that's not an option, at least, we should still rework __repr__ to either be a valid python expression (so that eval(repr(trans)) works, or alternatively enclose it in <...>. See https://docs.python.org/2/reference/datamodel.html?highlight=repr#object.__repr__

@ImportanceOfBeingErnest
Copy link
Member

One thing that might be useful is that when you type artist.__dict__ to get get a a dictionary without the long transform chain out.

@anntzer
Copy link
Contributor Author

anntzer commented May 5, 2018

Supplying both __str__ and __repr__ was suggested by @QuLogic in #9421 (comment)

I think best would be to provide both, or to use repr(array) insde in both cases at least to make the expression valid.

@jklymak
Copy link
Member

jklymak commented May 7, 2018

OK, I think we agreed on the call that

  1. __repr__ was unlikely to ever return a valid expression we can send to eval and hence should be enclosed in angle brackets.
  2. that __repr__ should be a one-liner that tells us what the object is.
  3. __repr__ should definitely not call __str__
  4. that __str__ should be the pretty-print version, with the indentation implimented in Improve reprs of transforms. #9421.
  5. I don't think there is anything at all incorrect about us supplying both, but

But this was just @efiring , @story645, and myself, so happy to dicsuss further, as that is hardly a quorum.

reference: https://docs.python.org/3/reference/datamodel.html#object.__repr__

@jklymak
Copy link
Member

jklymak commented May 7, 2018

See #11189 for the alternative as suggested by @timhoffm

@efiring
Copy link
Member

efiring commented May 8, 2018

Closing: alternative #11189 is merged.

@efiring efiring closed this May 8, 2018
@anntzer anntzer deleted the transformrepr branch May 8, 2018 04:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RecursionError when calling get_yaxis_transform() on a Symlog-scaled axis.
5 participants