John Prawyn
John Prawyn

Reputation: 1673

Is Python dict an Object?

I have a dict like this:

>>> my_dict = {u'2008': 6.57, u'2009': 4.89, u'2011': 7.74,
...            u'2010': 7.44, u'2012': 7.44}

Output with has_key:

>>> my_dict.has_key(unicode(2012))
True

Output with hasattr:

>>> hasattr(my_dict, unicode(2012))
False

I couldn't understand why this behaves differently. I googled and found out that it is because dict and objects are different.

But, still I couldn't understand the difference properly.

(BTW : I am using python 2.7)

Upvotes: 19

Views: 20905

Answers (5)

rnbguy
rnbguy

Reputation: 1399

attribute returns some property of an instance so that you can manipulate it. Now understand attribute will always return something, but if a key is not in d, d[key] will raise KeyError.

hasattr checks if an instantce has that attribute or not. Since dictionary keys are no attribute to the dictionary it returns False.

example :

# python3
>>> d = {1:True}
>>> dir(d) # this shows all the attributes of the instance
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__'
, '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__',
 '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '_
_new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__'
, '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get
', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
>>> hasattr(d,'keys')
True
>>> 1 in d.keys()
True

Upvotes: 0

immortal
immortal

Reputation: 3188

Dict is an object, as anything in Python is an object. There's, however, a difference between an objects attribute and a dicts key. The dict doesn't store its keys as attributes! The only way to access a dicts keys is through the __getitem__ method or the [] operator.

If you want to access the items this way, you can override the __getattr__ method and make it return the __getitem__ result in stead.

You can also create something like this:

   class ObjectDict(dict):
       def __init__(self, *args, **kws):
           super(ObjectDict, self).__init__(*args, **kws)
           self.__dict__ = self

Which will result in this behavior:

>>> d = ObjectDict()
>>> d['a'] = 3
>>> d.a
3
>>> hasattr(d, 'a')
True

But this is known to cause memory leaks in Python

Upvotes: 1

Martijn Pieters
Martijn Pieters

Reputation: 1123360

dict instances are objects too. But their keys are just not exposed as as attributes.

Exposing the keys as attributes (too or instead of item access) would lead to namespace pollution; you'd never be able to use a has_key key, for example. has_key is already an attribute on dictionaries:

>>> hasattr({}, 'has_key')
True
>>> {}.has_key
<built-in method has_key of dict object at 0x7fa2a8461940>

Attributes of objects and the contents of dictionaries are two separate things, and the separation is deliberate.

You can always subclass dict to add attribute access using the __getattr__() hook method:

class AttributeDict(dict):
    def __getattr__(self, name):
        if name in self:
            return self[name]
        raise AttributeError(name)

Demo:

>>> demo = AttributeDict({'foo': 'bar'})
>>> demo.keys()
['foo']
>>> demo.foo
'bar'

Existing attributes on the dict class take priority:

>>> demo['has_key'] = 'monty'
>>> demo.has_key
<built-in method has_key of AttributeDict object at 0x7fa2a8464130>

Upvotes: 33

kiriloff
kiriloff

Reputation: 26333

my_dict.has_key(unicode(2012)): has_key looks for a key in a dictionary. Keys in a dictionary are not attributes and

hasattr(object, name)

The arguments are an object and a string. The result is True if the string is the name of one of the object’s attributes, False if not. (This is implemented by calling getattr(object, name) and seeing whether it raises an exception or not.)

from which you can see that, although dict are objects, dict's keys are not the dict's attributes;

Upvotes: 2

Sukrit Kalra
Sukrit Kalra

Reputation: 34513

has_key checks for the existence of a key in the dictionary. (One your code defines while creating a dictionary) hasattr checks if the object has an attribute.

Dictionaries are objects, and they have certain attributes. hasattr checks for those.

>>> hasattr(dict, 'has_key')
True
>>> hasattr(dict, 'items')
True
>>> newDict = {'a': 1, 'b':2}
>>> newDict.has_key('a')
True

You can use dir() which lists out the valid attributes for an object.

>>> dir(dict)
['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues']

Upvotes: 3

Related Questions