214

While traversing a graph in Python, a I'm receiving this error:

'dict' object has no attribute 'has_key'

Here is my code:

def find_path(graph, start, end, path=[]):
    path = path + [start]
    if start == end:
        return path
    if not graph.has_key(start):
        return None
    for node in graph[start]:
        if node not in path:
            newpath = find_path(graph, node, end, path)
            if newpath: return newpath
    return None

The code aims to find the paths from one node to others. Code source: http://cs.mwsu.edu/~terry/courses/4883/lectures/graphs.html

Why am I getting this error and how can I fix it?

johnnyRose
  • 7,310
  • 17
  • 40
  • 61
Ashi
  • 2,149
  • 2
  • 9
  • 3

6 Answers6

312

has_key was removed in Python 3. From the documentation:

  • Removed dict.has_key() – use the in operator instead.

Here's an example:

if start not in graph:
    return None
johnnyRose
  • 7,310
  • 17
  • 40
  • 61
  • 2
    I think `key not in d.keys()` is probably *much* slower, too, since `key not in d` should be O(1) lookup and I believe `keys` produces a list, which is O(n) lookup (not to mention taking extra space in memory). I could be wrong about that though -- it might still be hashed lookup – Adam Smith Nov 16 '15 at 02:55
  • 3
    @AdamSmith not in Python 3, `d.keys()` is a view that implements most of the set interface. – Antti Haapala -- Слава Україні Jan 24 '17 at 16:24
  • 3
    It removed... but why ? Since it make python 2 port to python 3 more work to do. – 林果皞 Aug 08 '18 at 15:59
  • 1
    @林果皞: The whole point of a new major version is that the developers can introduce improvements which may include breaking changes instead of having to support old features as the language matures. This is always a risk which must be considered before upgrading to a new major version. In this case, `in` is shorter and more Pythonic, as well as being consistent with other collections in the language. – johnnyRose Aug 08 '18 at 16:26
66

In python3, has_key(key) is replaced by __contains__(key)

Tested in python3.7:

a = {'a':1, 'b':2, 'c':3}
print(a.__contains__('a'))
qloveshmily
  • 1,017
  • 9
  • 5
  • I think this is the right and easier way to do, Thank you for the answer – KK2491 Jan 19 '22 at 17:29
  • 3
    No, no, no... the `__contains__()` method is how you *implement* a containment test in a user-defined class, the `in` operator is how you actually *use* that test. About the only time you should ever explicitly call a double-underscored "magic" method is in a subclass method, as part of calling the superclass implementation. – jasonharper Jan 20 '23 at 14:33
30

has_key has been deprecated in Python 3.0. Alternatively you can use 'in'

graph={'A':['B','C'],
   'B':['C','D']}

print('A' in graph)
>> True

print('E' in graph)
>> False
Abhishek Pansotra
  • 947
  • 2
  • 13
  • 17
8

I think it is considered "more pythonic" to just use in when determining if a key already exists, as in

if start not in graph:
    return None
Kevin S
  • 2,595
  • 16
  • 22
  • 1
    I'm not sure, according to The Zen of Python(PEP 20): "Explicit is better than implicit". I think that if you use the `in` keyword, your intention might not be clear enough what does `if start not in graph:` means? may be `graph` is a list and it checks if there is no such string in the list? On the other hand, if you use syntax like `has_key` (now deprecated) or at least `in graph.keys()` it is more clear that `graph` is a `dict` – Amitay Drummer May 21 '20 at 20:09
6

Try:

if start not in graph:

For more info see ProgrammerSought

Godfrey
  • 1,001
  • 14
  • 17
4

The whole code in the document will be:

graph = {'A': ['B', 'C'],
             'B': ['C', 'D'],
             'C': ['D'],
             'D': ['C'],
             'E': ['F'],
             'F': ['C']}
def find_path(graph, start, end, path=[]):
        path = path + [start]
        if start == end:
            return path
        if start not in graph:
            return None
        for node in graph[start]:
            if node not in path:
                newpath = find_path(graph, node, end, path)
                if newpath: return newpath
        return None

After writing it, save the document and press F 5

After that, the code you will run in the Python IDLE shell will be:

find_path(graph, 'A','D')

The answer you should receive in IDLE is

['A', 'B', 'C', 'D']