-2

Just out of curiosity I'm playing with the __dict__ attribute on Python classes.

I read somewhere that a "class" in python is kind of a dict, and calling __dict__ on a class instance translate the instance into a dict... and I thought "cool! I can use this!"

But this lead me to doubts about the correctness and security of these actions.

For example, if I do:

class fooclass(object):
    def __init__(self, arg):
        self.arg1 = arg

p = fooclass('value1')
print(p.__dict__)
p.__dict__['arg2'] = 'value2'
print(p.__dict__)
print(p.arg2)

I have this:

>>>{'arg1': 'value1'}
>>>{'arg1': 'value1', 'arg2': 'value2'}
>>>value2

and that's fine, but:

  1. Does the fooclass still have 1 attribute? How can I be sure?
  2. Is it secure to add attributes that way?
  3. Have you ever had cases where this came in handy?
  4. I see that I can't do fooclass.__dict__['arg2'] = 'value2'.. so why this difference between a class and an instance?
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Hrabal
  • 2,403
  • 2
  • 20
  • 30
  • Your introduction is mostly nonsense. "I read somewhere that a "class" in python is kind of a dict". No it isn't. Most classes _have_ a dict, called `__dict__` for each instance, and another one for the class itself, but that doesn't mean they _are_ a dict. "and calling __dict__ on a class instance translate the instance into a dict". No. __dict__ isn't a function; you can't call it on an instance. And I'm not sure what it would even mean to "translate it into a dict". Again, most classes' instances _have_ a dict, and you can _access_ it, but… that's not close to what you seem to be saying. – abarnert Sep 12 '14 at 07:23

1 Answers1

5

You are altering the attributes of the instance. Adding and removing from the __dict__ is exactly what happens for most custom class instances.

The exception is when you have a class that uses __slots__; instances of such a class do not have a __dict__ attribute as attributes are stored in a different way.

Python is a language for consenting adults; there is no protection against adding attributes to instances with a __dict__ in any case, so adding them to the dictionary or by using setattr() makes no difference.

Accessing the __dict__ is helpful when you want to use existing dict methods to access or alter attributes; you can use dict.update() for example:

def Namespace(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

It is also helpful when trying to read an attribute on the instance for which there is a corresponding data descriptor on the class; to bypass the latter you can access the __dict__ on the instance to get to the attribute. You can also use this to test for attributes on the instance and ignore anything the class or the base classes might define.

As for fooclass.__dict__; you are confusing the class with the instances of a class. They are separate objects. A class is a different type of object, and ClassObj.__dict__ is just a proxy object; you can still use setattr() on the class to add arbitrary attributes:

setattr(fooclass, 'arg2', 'value2')

or set attributes directly:

fooclass.arg2 = value2

A class needs to have a __dict__ proxy, because the actual __dict__ attribute is a descriptor object to provide that same attribute on instances. See What is the __dict__.__dict__ attribute of a Python class?

Details about how Python objects work are documented in the Datamodel reference documentation.

Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343