By studying this question, you will improve your understanding of not only the fine details but also of the whole picture “object-oriented programming”.
So, let’s start by answering the two questions:
- What are static attributes?
- What are dynamic attributes?
What are static attributes?
In object-oriented programming, static attributes are usually defined for the class and shared among all instances. Here is a simple example:
class Book: # static attribute / class attribute classification = "textual" coffee_break_python = Book() hitchhikers_guide = Book() print(Book.classification) # textual print(coffee_break_python.classification) # textual print(hitchhikers_guide.classification) # textual
In the code, we define the static attribute “classification” for the class “Book”. You can access this attribute not only via the class name “Book” but also via the instances “coffee_break_python” and “hitchhikers_guide”. Think of it this way: the instance variables do not have their own attribute “classification”. Therefore, the interpreter tries to fix this by looking upwards the class hierarchy to find the first definition of the requested attribute “classification”. It finds the attribute on the class level.
Why are they called “static” in object orientation? Because they are allocated in memory “statically” for the whole run of the program — even before the first object is ever created.
Ok, you are ready for the first puzzle (assuming above definitions):
## Puzzle 1 Book.classification = "video" print(hitchhikers_guide.classification)
Commit to the answer first before reading on.
Most likely, you found the correct answer. The code snippet changes the value of the class attribute. The class instance “hitchhikers_guide” does not have its own definition of “classification”, so it lends the definition from the class attribute. The result is, therefore “video”.
Let’s have a look at this puzzle:
## Puzzle 2 Book.classification = "text" hitchhikers_guide.classification = "audio" print(coffee_break_python.classification)
I want you to lock your answer in first, before reading on. Make the commitment now. Have it? Good, then let’s see whether you guessed right.
What happens here?
1) You have a static class attribute.
2) You change it on the instance level (to “audio”).
3) You print the class attribute by calling it via another instance.
Hence the result is “audio”. Right?
The result is “text”. So why is that?
To understand this, you have to understand the concept of “dynamic attributes” first.
What are dynamic attributes in Python?
Dynamic attributes in Python are attributes for instances that you define dynamically at runtime (after creating the instances). In Python, everything is an object (even functions). So you can define a dynamic instance attribute for nearly anything.
Now, can you solve the following puzzle already?
## Puzzle 3 class Universe: None def answer(): return 42 u = Universe() u.answer = 21 answer.answer = 21 print(answer.answer + u.answer == answer())
Very confusing, I know. But commit to your “answer” first.
In the puzzle, we create two objects: the object “u” (obviously) and the function “answer” (not so obvious). Let’s not debate (for now) whether a class is an object as well… 😉
For both objects, we create a DYNAMIC ATTRIBUTE “answer”. The difference to the static attribute is that we define it at runtime for the objects themselves and not statically for the class. This is the answer to the question addressed in this email. (So many answers …)
The class “Universe” and all other potential instances of this class do not know the attribute “answer”. It is only defined for the instance “u” and the instance “answer”. That’s it.
By the way: the result for the puzzle 3 is “True”.
But more importantly, we can now understand why puzzle 2 produces the result “audio” and not “text”:
Book.classification = "text" hitchhikers_guide.classification = "audio" print(coffee_break_python.classification)
The first line talks about the static attribute of the class. This is the default attribute if an instance has not defined its own attribute.
The second line talks about the dynamic attribute of the instance “hitchhikers_guide”. It is only defined for this instance. So the book “coffee_break_python” does not know anything about the dynamic attribute of the other book. It only knows about the static attribute from the Book class.
To sum up, you have learned about the difference between static and dynamic attributes in Python. Static attributes are defined once for the class — and are used as a “fall-back” in case there are no explicit dynamic attributes defined for the instances. As soon as you try to “overwrite” a static attribute a by calling it the instance x (e.g. x.a = 1), you actually create a dynamic attribute on that instance that lives separately from any static attribute X.a for class X.
(Disclaimer: I know that the term “static attribute” is not so common in Python but I actually found it quite useful to explain things.)
Where to go from here?
Do you enjoy puzzle-based learning Python? I am doubling down on this unique way of learning Python because “practice testing” is scientifically proven to be one of the most effective learning techniques. Yet, I have not found any puzzle-based Python learning book on the market. That’s why I have written the Python textbook “Coffee Break Python” that is based 100% on a puzzle-based learning mindset. Get the book now!