When you write a class block, you create class attributes (or class variables). All the names that you have assigned in the class block, including the methods that you define with def , become class attributes.
After creating an instance of a class, everything that refers to an instance can create instance attributes on it. Inside the methods, the "current" instance is almost always associated with the name self , so you think of it as "self-variable variables." Typically, in an object-oriented design, code attached to a class must have control over the attributes of instances of this class, so almost all attribute attributes of an instance are executed inside the methods using the reference to the instance obtained in the self parameter of the method.
Class attributes are often compared with static variables (or methods), which can be found in languages ββsuch as Java, C # or C ++. However, if you want to strive for a deeper understanding, I would avoid thinking of class attributes as "the same" as static variables. Although they are often used for the same purpose, the basic concept is completely different. More on this in the Advanced section below the line.
Example!
class SomeClass: def __init__(self): self.foo = 'I am an instance attribute called foo' self.foo_list = [] bar = 'I am a class attribute called bar' bar_list = []
After executing this block, the SomeClass class SomeClass with three class attributes: __init__ , bar and bar_list .
Then we will create an instance:
instance = SomeClass()
When this happens, the SomeClass __init__ method is SomeClass , receiving a new instance in the self parameter. This method creates two instance attributes: foo and foo_list . This instance is then assigned to the instance variable, so it is associated with the thing with these two instance attributes: foo and foo_list .
But:
print instance.bar
gives:
I am a class attribute called bar
How did this happen? When we try to get the attribute through the syntax of the points, and the attribute does not exist, Python takes many steps to try and fulfill your request anyway. The next thing he will try is to look at the class attributes of the class of your instance. In this case, he found the bar attribute in SomeClass , so he returned this.
This is also the way method calls work. When you call mylist.append(5) , for example, mylist does not have an attribute named append . But the mylist class has and is associated with a method object. This method object returns the bit mylist.append , and then bit (5) calls the method with argument 5 .
The way this is useful is that all instances of SomeClass will have access to the same bar attribute. We could create a million instances, but we only need to store one line in memory, because they all can find it.
But you have to be a little careful. Look at the following operations:
sc1 = SomeClass() sc1.foo_list.append(1) sc1.bar_list.append(2) sc2 = SomeClass() sc2.foo_list.append(10) sc2.bar_list.append(20) print sc1.foo_list print sc1.bar_list print sc2.foo_list print sc2.bar_list
What do you think this prints?
[1] [2, 20] [10] [2, 20]
This is because each instance has its own copy of foo_list , so they were added separately. But all instances have access to the same bar_list . Therefore, when we did sc1.bar_list.append(2) , it affected sc2 , although sc2 did not exist yet! And also sc2.bar_list.append(20) affected the bar_list extracted through sc1 . This is often not what you want.
The following is an extended study. :)
To really pile up Python based on traditional statically typed OO languages ββsuch as Java and C #, you need to learn a bit to rethink classes.
In Java, a class is not in itself. When you write a class, you are more declaring a bunch of things that all instances of this class have. At run time, there are only instances (and static methods / variables, but in reality these are just global variables and the functions in the namespace associated with the class have nothing to do with OO). Classes are how you write in your source code what instances will be at runtime; they only "exist" in the source code, and not in the running program.
In Python, a class is nothing special. This is an object, like everything else. Thus, "class attributes" are actually exactly the same as "instance attributes"; in fact, there are simply "attributes." The only reason for distinguishing is that we tend to use objects that are classes other than objects that are not classes. The underlying mechanism is still the same. This is why I say that it would be a mistake to think of class attributes as static variables from other languages.
But what really makes Python classes different from Java style classes is that, like any other object , every class is an instance of some class !
In Python, most classes are instances of an inline class called type . It is this class that controls the general behavior of classes and makes all OO files like it. The default OO method for class instances that have their own attributes and have common methods / attributes defined by their class is just a Python protocol. You can change most of its aspects if you want. If you've ever heard of the use of a metaclass, this is all a definition of a class that is an instance of a different class than type .
The only really βspecialβ thing in classes (besides the whole built-in mechanism to make them work the way they do by default) is the syntax of the class block to make it easier to instantiate type :
class Foo(BaseFoo): def __init__(self, foo): self.foo = foo z = 28
roughly equivalent to the following:
def __init__(self, foo): self.foo = foo classdict = {'__init__': __init__, 'z': 28 } Foo = type('Foo', (BaseFoo,) classdict)
And it will ensure that all the contents of classdict become an attribute of the object being created.
So, it becomes almost trivial to see that you can access the attribute of the Class.attribute class as easily as i = Class(); i.attribute i = Class(); i.attribute . Both i and Class are objects, and objects have attributes. It also makes it easy to understand how you can change a class after it is created; just assign its attributes as you would with any other object!
In fact, instances have no special relationship with the class used to create them. The way Python knows which class is looking for attributes that are not found in the instance is the __class__ hidden attribute. What you can read to find out which class is an instance, just like with any other attribute: c = some_instance.__class__ . You now have the c variable associated with the class, although it probably does not have the same name as the class. You can use this to access class attributes or even call it to create more instances (even if you don't know what class it is!).
And you can even assign an i.__class__ to change the class it is an instance of! If you do, nothing special will happen immediately. It is not destructive. All of this means that when searching for attributes that do not exist in the instance, Python will go see the new __class__ content. Since this includes most methods, and methods usually expect the instance in which they are running to be in certain states, this usually leads to errors if you do it at random, and this is very confusing, but it can be done. If you are very careful, then the thing you store in __class__ should not even be a class object; all Python is going to look for attributes with it under certain circumstances, so all you need is an object that has the right attribute types (some caveats to the side where Python is really picky about things that are classes or instances of a particular class).
Most likely now. I hope (if you even read this far), I did not confuse you too much. Python is neat when you learn how it works. :)