Repository: pandas-dev/pandas

Issue:
items method only exists in python3
#### Code Sample, a copy-pastable example if possible

```python
for k, c in df.items():
    ...
```

#### Problem description

This works on python3 and fails on python2.  This seems like a natural thing to do to have easy duck-typing between dataframes and dicts of iterables.

Either the docs should be updated to flag this as a python3 only feature or `items` should be shimmed onto DataFrames for all versions of python.   In python2 this would have different semantics than `dict.item` given DataFrame has not had `item` before you are not changing behavior and the 'iterator-not-a-list' semantics are better.

It looks like the initial shim came in via 16dbeaba9ec2cc6d87636981644a08cb9bb9b2cd .

As a side-note, `six.iteritems` works as expected on DataFrames.


#### Expected Output

it does not raise.

#### Output of ``pd.show_versions()``

<details>

INSTALLED VERSIONS
------------------
commit: None
python: 2.7.13.final.0
python-bits: 64
OS: Linux
OS-release: 4.11.9-1-ARCH
machine: x86_64
processor: 
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: None.None

pandas: 0.20.3
pytest: 3.2.0
pip: 9.0.1
setuptools: 36.2.2.post20170724
Cython: None
numpy: 1.13.1
scipy: 0.19.1
xarray: None
IPython: 5.3.0
sphinx: None
patsy: None
dateutil: 2.6.1
pytz: 2017.2
blosc: None
bottleneck: None
tables: None
numexpr: None
feather: None
matplotlib: 2.0.2
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: None
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: 2.9.5
s3fs: None
pandas_gbq: None
pandas_datareader: None

</details>



Discussion:

Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -802,8 +802,7 @@ def itertuples(self, index=True, name="Pandas"):
         # fallback to regular tuples
         return zip(*arrays)
 
-    if compat.PY3:  # pragma: no cover
-        items = iteritems
+    items = iteritems
 
     def __len__(self):
         """Returns length of info axis, but here we use the index """
diff --git a/pandas/core/series.py b/pandas/core/series.py
--- a/pandas/core/series.py
+++ b/pandas/core/series.py
@@ -1110,8 +1110,7 @@ def iteritems(self):
         """
         return zip(iter(self.index), iter(self))
 
-    if compat.PY3:  # pragma: no cover
-        items = iteritems
+    items = iteritems
 
     # ----------------------------------------------------------------------
     # Misc public methods


Test patch:
diff --git a/pandas/tests/frame/test_api.py b/pandas/tests/frame/test_api.py
--- a/pandas/tests/frame/test_api.py
+++ b/pandas/tests/frame/test_api.py
@@ -171,7 +171,16 @@ def test_nonzero(self):
     def test_iteritems(self):
         df = self.klass([[1, 2, 3], [4, 5, 6]], columns=['a', 'a', 'b'])
         for k, v in compat.iteritems(df):
-            assert type(v) == self.klass._constructor_sliced
+            assert isinstance(v, self.klass._constructor_sliced)
+
+    def test_items(self):
+        # issue #17213, #13918
+        cols = ['a', 'b', 'c']
+        df = DataFrame([[1, 2, 3], [4, 5, 6]], columns=cols)
+        for c, (k, v) in zip(cols, df.items()):
+            assert c == k
+            assert isinstance(v, Series)
+            assert (df[k] == v).all()
 
     def test_iter(self):
         assert tm.equalContents(list(self.frame), self.frame.columns)
diff --git a/pandas/tests/series/test_api.py b/pandas/tests/series/test_api.py
--- a/pandas/tests/series/test_api.py
+++ b/pandas/tests/series/test_api.py
@@ -301,6 +301,16 @@ def test_iteritems(self):
         # assert is lazy (genrators don't define reverse, lists do)
         assert not hasattr(self.series.iteritems(), 'reverse')
 
+    def test_items(self):
+        for idx, val in self.series.items():
+            assert val == self.series[idx]
+
+        for idx, val in self.ts.items():
+            assert val == self.ts[idx]
+
+        # assert is lazy (genrators don't define reverse, lists do)
+        assert not hasattr(self.series.items(), 'reverse')
+
     def test_raise_on_info(self):
         s = Series(np.random.randn(10))
         with pytest.raises(AttributeError):