1

I was learning Python dictionaries at W3Schools:

car = {
  "brand": "Ford",
  "model": "Mustang",
  "year": 1964
}

x = car.items()

print(x)

I get:

dict_items([('brand', 'Ford'), ('model', 'Mustang'), ('year', 1964)])

The dict_items looks like a conversion function or class constructor, but it is not recognized at the command line:

>>> dict_items([('brand', 'Ford'), ('model', 'Mustang'), ('year', 1964)])

   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   NameError: name 'dict_items' is not defined

The most authoritative explanation I found is the Python documentation on dictionary view objects, but it still doesn't say anything about what dict_items is. Is it just a constructor that is not accessible to the public?

Chris_Rands
  • 38,994
  • 14
  • 83
  • 119
user36800
  • 2,019
  • 2
  • 19
  • 34
  • It's an `iterable` view that you you iterate over as shown https://docs.python.org/3/tutorial/datastructures.html#looping-techniques – Axe319 Apr 09 '21 at 17:47
  • 1
    What you are seeing with `dict_items([('brand', 'Ford'), ('model', 'Mustang'), ('year', 1964)])` is the `repr`. So in your case `for key, value in x: print(key, value)` prints out the keys and values. – Axe319 Apr 09 '21 at 17:49
  • @Axe319: Thanks, I read about iterables on-and-off over the past year. It doesn't really help me identify what the word `dict_items` refers to. But your explanation of `repr` makes a lot of sense! It might even explain a similar question I had about `dtype=' – user36800 Apr 09 '21 at 18:06
  • 1
    As an aside, "I was learning Python dictionaries at W3Schools" **don't**. W3Schools is notoriously bad. Just use the [official tutorial](https://docs.python.org/3/tutorial/) and documentation. – juanpa.arrivillaga Apr 09 '21 at 18:40
  • 1
    @user36800 the *word* `dict_items` is just part of the printed representation of that object. A dict_items object is an instance of a class, `dict_items`. That class isn't exposed anywhere, and it isn't in the built-in namespace so `dict_items` will be a `NameError`, although, you can trivially retrieve it using `dict_items = type({}.items())`. Note sure what you dont' understand exactly... There are many classes which are part of the Python runtime which are not in the built-in namespace, this isn't strange or unusual. – juanpa.arrivillaga Apr 09 '21 at 18:46
  • @juanpa.arrivillaga: Thanks for the pointer to the official tutorial. I actually don't stop with W3Schools, it's whatever I find via Google. What I didn't understand about dict_item was that it is presented to the user as a function invocation, and I was wondering if that was the case. – user36800 Apr 09 '21 at 21:47

1 Answers1

2

items() is a method implemented on the dict object that returns a iterable dictionary view.

The main noticeable difference from this and an iterator from a users perspective is you can iterate over the view multiple times whereas an iterator gets consumed. And still maintain the memory savings, since as @ juanpa.arrivillaga pointed out, it is only a wrapper around the underlying structure.

It's implementation seen here is implemented in C as dict_items which would explain the repr.

What can you do with this view? Well typically you see it used directly in a for loop such as:

for key, value in dct.items():
    print(key, value)

When iterated over it returns a key, value tuple for each dict entry which is typically unpacked into 2 variables as shown above.

You may also notice dict.keys() and dict.values() which work in a similar fashion but for the keys and values individually.

Now onto the __repr__. When you create a python object.

class MyClass:
    pass
foo = MyClass()
print(foo)

It gives a default representation of the object and its memory location. Something like

<__main__.MyClass object at 0x0175F718>

This looks kind of ugly and isn't very informative.

You can override this behavior by defining a __repr__ method returning what you want it to display. Typically, this is the class name and the arguments it was called with.

So

class MyClass:
    def __init__(self, x):
         self.x = x
    def __repr__(self):
         return f'MyClass(x={self.x})'
foo = MyClass(3)
print(foo)

would return

MyClass(x=3)
Axe319
  • 4,255
  • 3
  • 15
  • 31
  • 1
    It isn't "lazy evaluation". It's a *view*, which basically is just a wrapper over some other data structure, that lets you "view" the data without copying the underlying structure – juanpa.arrivillaga Apr 09 '21 at 18:36
  • Maybe lazy evaluation isn't the best term. I'll remove it. – Axe319 Apr 09 '21 at 18:43
  • Also, that [link](https://github.com/python/cpython/blob/6f37ebc61e9e0d13bcb1a2ddb7fc9723c04b6372/Objects/dictobject.c#L2321) is actually *not* the implementation of `dict.items`... taht seems to be the old implementation that returned a list of tuples... probably kept around for internal use. [This is the actual method directly](https://github.com/python/cpython/blob/6f37ebc61e9e0d13bcb1a2ddb7fc9723c04b6372/Objects/dictobject.c#L4873) which just calls [this helper function](https://github.com/python/cpython/blob/6f37ebc61e9e0d13bcb1a2ddb7fc9723c04b6372/Objects/dictobject.c#L4211) – juanpa.arrivillaga Apr 09 '21 at 18:52
  • That helper method eventually makes an actual view object. [Here's the associated C structure that corresponds to the `dict_items` type](https://github.com/python/cpython/blob/6f37ebc61e9e0d13bcb1a2ddb7fc9723c04b6372/Objects/dictobject.c#L4839) and it's associated methods. – juanpa.arrivillaga Apr 09 '21 at 18:54
  • Thank you, Axe319, for the deep explanation, and juanpa.arrivillaga, for suggesting improvements. – user36800 Apr 09 '21 at 21:51