ENH: pd.DataFrame.info() to show line numbers GH17304
State: closed

- [x] closes #17304
- [x] tests updated and passed
- [x] passes flake8 diff
- [x] whatsnew entry

Refactored to  `self.columns` and `len(self.columns)`

New output
```
>>> import pandas as pd
>>> df = pd.DataFrame(pd.np.random.rand(4, 10), 
                      columns=['%s%s' % (x, pd.np.random.randint(2, 10)*'a') for x in range(10)])
>>> df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 10 columns):
 #.  Column        Non-Null Count & Dtype
---  ------        ----------------------
 0   0aaaaaaaaa    4 non-null float64
 1   1aaaaa        4 non-null float64
 2   2aaaaaa       4 non-null float64
 3   3aaaaaa       4 non-null float64
 4   4aaaaaa       4 non-null float64
 5   5aaaaaaa      4 non-null float64
 6   6aa           4 non-null float64
 7   7aaaaaaa      4 non-null float64
 8   8aaaaaaa      4 non-null float64
 9   9aaaaaaaaa    4 non-null float64
dtypes: float64(10)
memory usage: 392.0 bytes
```

Labels:
name: Enhancement
name: Error Reporting
description: Incorrect or improved errors from pandas

Comments:
Thanks for the PR!  Just address the test failures and add a `whatsnew`, and you should be set I think.
I find 1 based indexing confusing since  `df.iloc[:,1]` will not be the column indexed as 1.

Maybe a header:

```
Data columns (total 10 columns):
Index  Column   Non-Null Count
-----  ------       ----------
 0     0aaaaa       4 non-null float64
 1     1aa          4 non-null float64
```
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=h1) Report
> Merging [#17332](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/96f92eb1c696723b6465fdc273dc8406201c606a?src=pr&el=desc) will **decrease** coverage by `0.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/17332/graphs/tree.svg?width=650&height=150&src=pr&token=eZ4WkYLtcO)](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #17332      +/-   ##
==========================================
- Coverage   91.01%   90.99%   -0.02%     
==========================================
  Files         162      162              
  Lines       49567    49570       +3     
==========================================
- Hits        45113    45107       -6     
- Misses       4454     4463       +9
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `88.77% <100%> (ø)` | :arrow_up: |
| #single | `40.24% <0%> (-0.07%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `97.72% <100%> (-0.1%)` | :arrow_down: |
| [pandas/io/gbq.py](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=tree#diff-cGFuZGFzL2lvL2dicS5weQ==) | `25% <0%> (-58.34%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=footer). Last update [96f92eb...234b042](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=h1) Report
> Merging [#17332](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/da6e26db079cd4050c1693939db6a52afb2978e1?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/17332/graphs/tree.svg?src=pr&width=650&token=eZ4WkYLtcO&height=150)](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #17332      +/-   ##
==========================================
+ Coverage   91.92%   91.92%   +<.01%     
==========================================
  Files         160      160              
  Lines       49913    49926      +13     
==========================================
+ Hits        45882    45895      +13     
  Misses       4031     4031
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.3% <100%> (ø)` | :arrow_up: |
| #single | `42.09% <0%> (-0.02%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/17332/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `97.21% <100%> (+0.01%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=footer). Last update [da6e26d...7c13220](https://codecov.io/gh/pandas-dev/pandas/pull/17332?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

@gfyoung -- Changes have been pushed, any thoughts?
@jreback -- updated with @bashtage proposed style (0-index with header)
Have you checked with very long column names and all possible dtypes?  Just wondering if it always is readable on say 80 columns.
@bashtage -- some samples

```
In [20]: df = pd.DataFrame(np.random.rand(4, 10), columns=[
    ...:         '%s%s' % (x, np.random.randint(2, 50)*'a') for x in range(10)])

In [21]: df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 10 columns):
 #.  Column                                               Non-Null Count & Dtype
---  ------                                               ----------------------
 0   0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa         4 non-null float64
 1   1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa    4 non-null float64
 2   2aaaaaa                                              4 non-null float64
 3   3aaaaaaaaaaaaaaaaaaaaaaaaaaaaa                       4 non-null float64
 4   4aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa                  4 non-null float64
 5   5aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa               4 non-null float64
 6   6aaaaaaaaaaaaaaaaaaaa                                4 non-null float64
 7   7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa                   4 non-null float64
 8   8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa      4 non-null float64
 9   9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa       4 non-null float64
dtypes: float64(10)
memory usage: 392.0 bytes

In [22]: df = pd.DataFrame(np.random.rand(4,4), columns=['%s' % x for x in range(4)])

In [23]: df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 4 columns):
 #.  Column    Non-Null Count & Dtype
---  ------    ----------------------
 0   0         4 non-null float64
 1   1         4 non-null float64
 2   2         4 non-null float64
 3   3         4 non-null float64
dtypes: float64(4)
memory usage: 200.0 bytes

In [16]: df.info(null_counts=False)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 4 columns):
 #.  Column    Dtype
---  ------    -----
 0   0         float64
 1   1         float64
 2   2         float64
 3   3         float64
dtypes: float64(4)
memory usage: 200.0 bytes

In [24]: pd.DataFrame({'A': np.random.randn(5),
    ...:               'B': pd.date_range('1/1/2000', periods=5),
    ...:               'C': ['c']*5,
    ...:               'D': [1]*5}).info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 4 columns):
 #.  Column    Non-Null Count & Dtype
---  ------    ----------------------
 0   A         5 non-null float64
 1   B         5 non-null datetime64[ns]
 2   C         5 non-null object
 3   D         5 non-null int64
dtypes: datetime64[ns](1), float64(1), int64(1), object(1)
memory usage: 232.0+ bytes
```
space constructor takes care of column character length and verbosity defaults to provided settings. 
can you rebase / update
I've rebased, not sure what is causing the lint issue. The diff seems flake8 fine.
```
Check for use of lists instead of generators in built-in Python functions
pandas/core/frame.py:            space = max([len(pprint_thing(k)) for k in cols])
```
pushed a commit to fix
@jreback -- Thanks for that.
can you rebase and update
this looked ok if we can comeback and rebase it @pandas-dev/pandas-core 
@jreback @jorisvandenbossche -- using `#.` instead of `Index` for the line number column. Below are the sample outputs. Moved this to `0.24.0` whatnew section

```ipython
In [20]: df = pd.DataFrame(np.random.rand(4, 10), columns=[
    ...:         '%s%s' % (x, np.random.randint(2, 50)*'a') for x in range(10)])

In [21]: df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 10 columns):
 #.  Column                                               Non-Null Count & Dtype
---  ------                                               ----------------------
 0   0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa         4 non-null float64
 1   1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa    4 non-null float64
 2   2aaaaaa                                              4 non-null float64
 3   3aaaaaaaaaaaaaaaaaaaaaaaaaaaaa                       4 non-null float64
 4   4aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa                  4 non-null float64
 5   5aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa               4 non-null float64
 6   6aaaaaaaaaaaaaaaaaaaa                                4 non-null float64
 7   7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa                   4 non-null float64
 8   8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa      4 non-null float64
 9   9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa       4 non-null float64
dtypes: float64(10)
memory usage: 392.0 bytes

In [22]: df = pd.DataFrame(np.random.rand(4,4), columns=['%s' % x for x in range(4)])

In [23]: df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 4 columns):
 #.  Column    Non-Null Count & Dtype
---  ------    ----------------------
 0   0         4 non-null float64
 1   1         4 non-null float64
 2   2         4 non-null float64
 3   3         4 non-null float64
dtypes: float64(4)
memory usage: 200.0 bytes

In [16]: df.info(null_counts=False)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 4 columns):
 #.  Column    Dtype
---  ------    -----
 0   0         float64
 1   1         float64
 2   2         float64
 3   3         float64
dtypes: float64(4)
memory usage: 200.0 bytes

In [24]: pd.DataFrame({'A': np.random.randn(5),
    ...:               'B': pd.date_range('1/1/2000', periods=5),
    ...:               'C': ['c']*5,
    ...:               'D': [1]*5}).info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 4 columns):
 #.  Column    Non-Null Count & Dtype
---  ------    ----------------------
 0   A         5 non-null float64
 1   B         5 non-null datetime64[ns]
 2   C         5 non-null object
 3   D         5 non-null int64
dtypes: datetime64[ns](1), float64(1), int64(1), object(1)
memory usage: 232.0+ bytes
```
What about iloc instead of #.? If staying with # the . seems unnecessary.

On Mon, Jul 9, 2018, 19:03 Pratap Vardhan <notifications@github.com> wrote:

> @jreback <https://github.com/jreback> @jorisvandenbossche
> <https://github.com/jorisvandenbossche> -- using #. instead of Index.
> Below are the sample outputs. Moved this to 0.24.0 whatnew section
>
> In [20]: df = pd.DataFrame(np.random.rand(4, 10), columns=[
>     ...:         '%s%s' % (x, np.random.randint(2, 50)*'a') for x in range(10)])
>
> In [21]: df.info()
> <class 'pandas.core.frame.DataFrame'>
> RangeIndex: 4 entries, 0 to 3
> Data columns (total 10 columns):
>  #.  Column                                                Non-Null Count
> ---  ------                                                --------------
>  0   0aaaaaaaaaaaaaa                                       4 non-null float64
>  1   1aaaaa                                                4 non-null float64
>  2   2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa              4 non-null float64
>  3   3aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa      4 non-null float64
>  4   4aaaaaaaaaaaaaaaaaaaa                                 4 non-null float64
>  5   5aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa          4 non-null float64
>  6   6aaaaaaaaaaaaa                                        4 non-null float64
>  7   7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa              4 non-null float64
>  8   8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa            4 non-null float64
>  9   9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa    4 non-null float64
> dtypes: float64(10)
> memory usage: 392.0 bytes
>
> In [22]: df = pd.DataFrame(np.random.rand(4,4), columns=['%s' % x for x in range(4)])
>
> In [23]: df.info()
> <class 'pandas.core.frame.DataFrame'>
> RangeIndex: 4 entries, 0 to 3
> Data columns (total 4 columns):
>  #.  Column    Non-Null Count
> ---  ------    --------------
>  0   0         4 non-null float64
>  1   1         4 non-null float64
>  2   2         4 non-null float64
>  3   3         4 non-null float64
> dtypes: float64(4)
> memory usage: 200.0 bytes
>
> In [24]: pd.DataFrame({'A': np.random.randn(5),
>     ...:               'B': pd.date_range('1/1/2000', periods=5),
>     ...:               'C': ['c']*5,
>     ...:               'D': [1]*5}).info()
> <class 'pandas.core.frame.DataFrame'>
> RangeIndex: 5 entries, 0 to 4
> Data columns (total 4 columns):
>  #.  Column    Non-Null Count
> ---  ------    --------------
>  0   A         5 non-null float64
>  1   B         5 non-null datetime64[ns]
>  2   C         5 non-null object
>  3   D         5 non-null int64
> dtypes: datetime64[ns](1), float64(1), int64(1), object(1)
> memory usage: 232.0+ bytes
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/pandas-dev/pandas/pull/17332#issuecomment-403567936>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AFU5RWA_nNf26qQTauJe2aCr--2jaXxCks5uE5rVgaJpZM4PCYU5>
> .
>

Closing as stale. Ping if you'd like to continue
@WillAyd What was left to be done? I can try finishing it up
@rotuna if you'd like to pick up you can make your own branch off of this, merge in master, address comments above and post your own PR

Note we've had a lot of stylistic changes to our code since this was started (namely introducing black) so might be a large diff