It's also possible to abuse this in some odd ways. You can
add a member to an object, even if not methods in that
object know anything about that member. For example:
class Foo:
def __init__(s):
a=1
return s
if __name__=='__main__':
example = Foo()
example.zebra="Intruder Alert!"
print example.zebra
This is a curiosity. I don't know of a valid programming
reason to use this feature. But basically every object
in Python is like an independent variable namespace; and
that name space can contain any number of variables just
as our global namespace can.
However, another oddity of Python is that we must
explicity use self.XXX to refer to our members; there
is no default to a lexical scope.
It seems to me that class fields defined outside of methods behave only superficially like static fields. As far as I can tell (from experimentation, not from examining the implementation), only mutable data types which are defined outside of methods behave like static fields. In the below example, "she" still weighs 100 after we have set the weight of a witch to 'duck'
>>> class person :
... weight = 100
...
>>> witch = person()
>>> she = person()
>>> witch.weight
100
>>> she.weight
100
>>> witch.weight = 'duck'
>>> witch.weight
'duck'
>>> she.weight
100
However, if weight is contained in a list, it is 'static':
>>> class person :
... weight = [100]
...
>>> witch = person()
>>> she = person()
>>> witch.weight
[100]
>>> she.weight
[100]
>>> witch.weight[0] = 'duck'
>>> witch.weight
['duck']
>>> she.weight
['duck']
I assume that this is because the reference contained in person.weight is shared between different instantiations. This came back to haunt me before I understood what was going on.
You can also change a class variable after the fact.
It will change the child object values for those
instances which haven't had their values explicitly
set. In this sense, properties at the class level
serve as defaults which may be overridden at the
instance level.
>>> class Person:
weight = 200
>>> a = Person()
>>> b = Person()
>>> a.weight
200
>>> b.weight
200
>>> b.weight = 90 # this adds a property to the instance
>>> a.__dict__ # still empty
{}
>>> b.__dict__ # because of assignment
{'weight': 90}
>>> Person.weight = "Eighty" # change at the class level
>>> b.weight # unchanged because it has its own 'weight'
90
>>> a.weight # still looks to parent for value
'Eighty'
Consider this. Python thinks, probably, that a program is interested essentially in the behavior of a given class of objects. The program has objects talking to one another simply be invoking various behaviors defined as methods. The program need not be interested overly as to how the state of objects are maintained internally. Whether the components of an objects are laid out in one way or the other is of least interest. Hence methods should be able to add comonents to the objects as they think required. Talking about the size of the object is some what unwarrented in pure OO context. I am not an expert in Python and hence I could be wrong; but I am inclined to think that this is the case.