Displaying results: Using `print()` vs. calling method/function directly

I’ve tried searching the forums and I went down several rabbit holes thanks to Google, but I’m still not understanding the difference in how results are displayed.

I can’t really copy/paste results to show what I mean and I have a great dislike of screenshots so I’m hoping that whoever is reading this knows what I mean when I say the outputs are quite different between (for example) df.head() and print(df.head()). Why is that?

I really like using print() because I can add leading/trailing text and add line breaks to help make the output more readable and meaningful but the ‘table’ that is displayed looks awful compared to just calling df.head() alone.

Can someone explain to me what’s happening here? I feel like this has something to do with string or __str__ somewhere…somehow? Ok, someone please save me because I’m obviously starting to spiral here :laughing:

1 Like

class testprint():
    def __repr__(self):
        return 'hard to read repr'
    def __str__(self):
        return 'easy to read str'
    
testprint()
print(testprint())

class testprintwithoutrepr():
    def __str__(self):
        return 'easy to read str'
    
testprintwithoutrepr()
print(testprintwithoutrepr())

class testprintwithoutstr():
    def __repr__(self):
        return 'hard to read repr'
    
testprintwithoutstr()
print(testprintwithoutstr())

class testprintwithoutboth():
    pass
testprintwithoutboth()
print(testprintwithoutboth())

This is how you can do your own experiment, to tease out the api behaviour as a blackbox. This skill is useful for learning other frameworks too, like sklearn’s pipeline api (fit_transform,transform) when writing custom transformers and tensorflow custom models with all their input_fn and model_fn or selenium when you want to change how waits (https://selenium-python.readthedocs.io/waits.html) are implemented so they go faster/do less defensive programming.

Basically, __str__ is the human readable interpretation. __repr__ is the machine readable interpretation, meaning if you copied the output of a well designed __repr__ (one that returns the class attributes available and their initialized values) and ran it, it should have constructed the same class that showed that __repr__ output. My __repr__ was just randomly designed to show precedence vs __str__.

print looks for __str__ first, if missing it goes for __repr__.
Showing it without print (the nice displayed html people usually use for dataframe viz) will use the __repr__

I don’t think people practically ever try to make both __repr__, __str__ missing because it’s indecipherable and makes both implicit/explicit prints lose their purpose. I have no idea for the last case why the print output shows object and what it means.

You can create the nice display explicitly with HTML() and display(): https://stackoverflow.com/questions/26873127/show-dataframe-as-table-in-ipython-notebook

2 Likes

Thank you, thank you, thank you! Although I had to read it several times to wrap my head around it, I finally understand what you are doing here…and I love it! I am a huge fan of troubleshooting and this “blackbox” strategy speaks to me on so many levels.

I didn’t know it when I asked the question, but this is exactly the explanation I wanted, and more. I really appreciate it since I will be tinkering with tensorflow in the not-so-distant future. Some of your answer is still lost on me but I figure that’s okay…I can’t expect to understand everything after just 5-6 weeks of learning! It’s more like 11-12 weeks where you “start to know everything,” right? :sunglasses:

Once more, thank you for taking the time to compose this in-depth answer. It is greatly appreciated.

I’m glad you learned something from it. Yes, I would say 12 weeks would be sufficient to get the syntax and be comfortable with implementing ideas in code. Beyond that, learning becomes how much you actively expose yourself to new methods of doing the same thing, or using the same method in new contexts.
For eg. people may think x/y-lim in a matplotlib is not so important, but it can effectively be used to zoom in to see dense areas of overlapping points more clearly.
Itertools recipes is frequently used collection of snippets since iteration is at the core of programming. My favourite is grouper, also because that fish tastes great. https://docs.python.org/3/library/itertools.html#itertools-recipes