Why does Python allow instance variables to be added after initialization?
Question: 
    class MyClass(object):
        class_var = []
        def __init__(self, i_var):
            self.i_var = i_var
    
    a = MyClass(2)
    a.hit = 1
    print a.hit
    

As we can see, `hit` is added to `a` as an instance variable after
initialization. What's a good reason to allow defining instance variable in
such a way? And, is it dangerous?


Answer: > What's a good reason to allow defining instance variable in such a way?

I think it's important to note that `self` inside your `__init__` function is
exactly the same as `self` in any other method on that instance. It's also the
same as `a` outside the class. The magic of the `__init__` method lies in
_when_ it gets called and nothing else (which is true of _all_ python magic
methods). To have `__init__` "freeze" the object in one way or another would
go against the way things have always been done in python.

So, I would say that the "good reason" is because it makes things very
consistent.

> And, is it dangerous?

Yes. It can be.

The practice of _intentionally_ adding methods/attributes to an instance is
known as Monkey Patching (also occasionally called Duck Punching)1 \-- And it
really shouldn't be done unless you don't have any other options.

The practice of _unintentionally_ adding methods/attributes to an instance is
known as creating bugs (and we've all done it :-).

Fortunately, there are tools to help you prevent these types of bugs. Linters
are the most common. I personally use `pylint` to help warn me about these
sorts of bugs.

Between the linter and using common sense (see above about not Monkey
Patching), I've very rarely been hit with a hard-to-track bug because of this
part of python's ideology.

1I suppose that it isn't duck punching if you add more attributes in a later
instance method -- But you probably shouldn't be doing that either . . .

