6

If I make a class instance like this

class MyClass(object):
    pass
x = MyClass()

I can then set attributes on x as follows:

x.myAttr = 1 or x.__setattr__('myAttr', 1)

However, if I make a dict

d = {}

I cannot set attributes on it. For example, if I do this

d.__setattr__('myAttr', 1)

I get the error " 'dict' object has no attribute 'myAttr' " The same thing happens if I try

d.myAttr = 1

I have noticed that in the case of x.myAttr = 1 what actually happens is that

x.__dict__

gets updated with a new key, so it must be that

d.__setattr__

doesn't work because d doesn't have

d.__dict__

simply because d is a dict. I would appreciate it very much if someone could thoroughly explain what's going on here.

Do all python objects have .__dict__?

Why does my attempt at calling d.__setattr__ result in an error saying that the attribute doesn't exist?

Is there a specific heirarchy of built-in types that I should know about? A simple reference would be much appreciated.

python 2.6.4

Windows XP Pro x64 SP2

5 Answers 5

5

A dict instance doesn't have a __dict__ attribute, so you can't assign attributes on it. Most of Python's built-in classes (which are written in C and define attributes differently) don't. If you subclass dict, the subclass will have a __dict__ attribute and you can then add attributes to instances of the subclass.

Sign up to request clarification or add additional context in comments.

3 Comments

I see. So is it in some sense correct to imagine that self.__setattr__ works as self.__setattr__(name, value) <=> self.__dict__.__setitem__(name, value)?
@MartinisGroup No, it does not have do. It can (and is, e.g. in some libraries) be overriden to do something different. Also, while you didn't explicitly say so, you seem to think that __setattr__ is the key to attribute assignment. It isn't, descriptors (e.g. properties) also have a role and built-in objects are weird in any case.
Yeah, "built-in objects are weird" cuts to the root of things.
3

copy-paste from docs.python.org:

A special attribute of every module is __dict__. This is the dictionary containing the module’s symbol table. Modifying this dictionary will actually change the module’s symbol table, but direct assignment to the __dict__ attribute is not possible (you can write m.__ dict__['a'] = 1, which defines m.a to be 1, but you can’t write m.__dict__ = {}). Modifying __dict__ directly is not recommended.

http://docs.python.org/library/stdtypes.html

The method

Both lines do the same:

x.__setattr__('a', b)
x.a = b

Like __ add__ is:

x.__add__(b)
x + b

However, you can redefine a dict.__ setattr__ function to whatever you want

edit for 3rd comment:

class x(object):
    def __init__(self):
        pass
    def __setattr__(self, a, b):
        print "nope, i will not set the attribute %s = %s" % (a,b)

c = x()
c.a = 4
print c.__dict__

will print "nope, i will not set the attribute a = 4 and c.__dict__ won't have the attribute 'a'

3 Comments

I understand that foo.__setattr__('a', b) does the same thing as foo.a = b. What I don't understand is why I can't do either of these on a dict.
because dict object has __setattr__ defined like he wants to
Ok, your edit for 3rd comment implies that self.__setattr__(name, val) invokes something like self.__dict__.__setitem__(name, val). Is this correct?
1

Explanation of exception:

>>> class C(object):
...     __slots__ = ('a', 'b')
... 
>>> c = C()
>>> c.a = 1
>>> c.t = 2
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'C' object has no attribute 't'

slots described here

2 Comments

Does your post imply that slots is used by built in types in a way that disallows doing setattr on dict instances? Please explain how your post answers my original questions ^^
@Martinis Group, dict type are implemented in code of interpreter, and can not be changed - only subclassed. slots can be used in user defined classes
0

self.__dict__ is a dict. Suppose, dict also had a __dict__, its a recursive definition and things wont work :-)

Comments

0

If you do x.myAttr = 1, you are really doing x.__dict__['myAttr'] = 1. If you did x.__dict__.myAttr you would get the same error as with d.myAttr. The .attribute assignment is defined for classes but not dicts - dict assignment is via d['attribute'] instead.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.