Python Class Variables: Explained
In programming, a variable is a representation of a piece of data. variable can be named almost anything — and the value stored within the variable can be anything. A variable name cannot begin with a number, and must be alphanumeric. Here is an example of variables inPython:
>>> x = 40 >>> x 40 >>> y = 75 >>> y 75 >>> z = x + y #<—Combining variables to store in a new variable >>> my_car = "Chevy Impala" >>> my_car_milate = 10000.21 >>> "My car is a " + my_car + " and it's milage is at " + str(my_car_mileage) "My car is a Chevy Impala and it's milage is at 1122.1" >>>
As shown in the example above, a variable really can hold anything — from integers to decimals to words.
Python is an object-oriented programming language (OOP), meaning that classes are used to represent the structure of the data we wish to manipulate. With respect to OOP, variables can be stored in two forms: instance variables and class variables. Having a solid foundation of Object-Oriented Programming will make learning Python much easier.
What is a Class
A class is a representation of the data we wish to use in a programming language. Think of it as a way of storing related data in a logical manner. A class serves as a blueprint to build objects, and these objects are generally stored in variables and passed around the program. Let's look at a quick example.
>>> class Dog: … def bark(self): … print "I"m a dog. Bark bark!" … def woof(self): … print "I'm a BIG dog. WOOF WOOF." … def yip(self): … print "I'm a little dog. YIP YIP." >>> saint_bernard = Dog() #<—Creating an instance of the class. >>> saint_bernard.woof() >>> I'm a BIG dog. WOOF WOOF. >>> chow_chow = Dog() >>> chow_chow.bark() I'm a dog. Bark bark!
In the example above, we are creating a class called Dog. Dog is a simple class that takes three methods: bark, yip, and woof. Think of a method as a recipe. It takes parameters or no parameters in this case and performs some operation related to the class.
After creating the class, we instantiate the class. I.E, stored it in a variable called saint_bernard and chow_chow. After instantiating the class, we called two methods, which printed out the words we programmed earlier. So what does all this have to do with variables? A lot actually, let's take a look at what class variables are and how to use them to spice up our Dog class.
>>>class Dog: … legs = 4 #<— class variable … def bark(self): print "I’m a dog. Bark bark!"
What is a Class Variable?
A class variable is a variable that is scoped to the entire class. In computer science, the scope of a variable is the area or namespace in which the variable binding is valid. So that means all methods within a class will be able to use class variables. Let's see it in action by rewriting or Dog class from earlier.
>>> poodle = Dog() >>> labrador = Dog() >>> poodle.legs 4 >>> labrador.legs 4
Above is an example of a class variable called legs. Generally a class variable will be something that will not change often. The special property of a class object is that changing it will affect every instantiation of that class created. This is a double-edged sword, because on the one hand it may be convenient because it will change all the objects that were created. On the other hand, it could break some business logic that relied on that variable never mutating. Let's jump into some code.
We created two instances of the Dog class: one called poodle and the other Labrador.
>>> Dog.legs = 5 >>> Dog.legs 5 >>> poodle.legs 5 >>> labrador.legs 5
We then called the class variable. However, what if the poodle by some miracle grew another leg? In that case we would have to make sure our class reflects this new reality by changing the legs variable.
>> class Dog: legs = 4 #<–class variable def __init__(self, name, breed, age): self.name = name #<—instance variable self.breed = breed #<—instance variable self.age = age #<—instance variable.
Uh-oh! Can you spot what happened? We changed the class variable to 5 at the top of our code, but that changed the amount of legs for both Labrador and Poodle. So to
drive it home, it's really important not to change the class variable unless you want to change it for every object instantiated.
With that being said, here is how it would be changed for just the poodle:
>>> poodle.legs = 5 >>> poodle.legs 5 >>> labrador.leg 5 >>> poodle.__class__.legs
In this example, we changed the amount of legs on the individual object called poodle.
As you can see, it did not affect the Labrador. However, it is important to note that changing it on the poodle did not actually change the class variable itself. The final call is on the class variable itself.
So in other words, each object has an instance of the class variable. Hopefully you see where we're going with this, so let's look more in-depth at instance variables.
What is an Instance Variable?
An instance variable is a variable that is only scoped to the particular instantiation of a class. Here is some code to illustrate an instance variable.
>>> class Dog: legs = 4 #<—class variable def __init__(self, name, breed, age): self.name = name #<—instance variable self.breed = breed self.age = age
In our souped up version of Dog class, we have created an initializer with three instance variables. An initializer can be used to perform pre-processing on a newly instantiated class, as well as populate the instance variables like so:
>>> dog1 = Dog("Hershey", "Chow Chow", 18) >>> dog2 = Dog("Spartacus", "Rat Terrier", 5) >>> dog1.name 'Hershey' >>> dog2.name 'Spartacus' >>> dog2.breed 'Rat Terrier' >>> Dog.legs 4 >>> Dog.breed Traceback (most recent call last): File "<stdin>", line 1 in <module> AttributeError: class Dog has no attribute 'breed'
There is a lot going on in this code snippet, so let's break it down a bit. We created two Dog objects: dog1 and dog2. We invoked two of their instance variables, which provided us with the information we supplied earlier.
Then we called Dog.legs, which naturally provided the number four. However, notice that Dog.breed threw an error. That is because the breed variable is only available as an instance variable. It is not shared across the entire class.
Here is a good way to sum up the relationship: a class variables is shared by all objects that are created. An instance of the class variable is always created on each newly minted object; it overrides the class instance. Lastly, an instance variable is only accessible to the object it was defined in.
How to Prevent Class Variable Mutation
Warning: The following code will only work in Python 3.x
In computer science, the changing of variables is called mutating. If an object or variable cannot change, it is said to be immutable. Often, you don't want people coming into your code and changing the class variables. As code gets more and more complex, changing something with such a wide scope could have far ranging consequences. Luckily, Python has a way of fixing that. It's a little more on the advanced side, but it is worth taking a look.
First, create a class with a class variable that you never want anyone to change. Let's face it: it is inherent to the nature of a dog to have four legs, so we will make this an immutable characteristic in our code. Here is an example:
class CantChangeClassVariable(type): def __setattr__(self, key, value): raise ValueError(key) class Dog(metaclass=CantChangeClasssVariable): legs = 4 def __init__(self, name, breed, age): self.name = name self.breed = breed self.age = age
There is nothing too special about the Dog class, except for a couple things. The first thing being metaclass=CantChangeClassVariable. Metaclass is a way of describing how the class should be active in certain situations. In this case, I wrote a simple class called CantChangeVariable. Whenever a class variable is changed, raise a Value Error. This is how it looks in action.
Import Dog If __name__ == '__main__': some_dog = Dog.Dog("Fido", "Lab", 10) print("My dog has " + str(some_dog.legs) + " legs.") #<—printing instance variables…works fine. some_dog.legs = 5 #<—Change the instance variable…works fine. print("Now my dog has " + str(some_dog.legs) + " legs.") Dog.Dog.legs = 32 #<—This will break now. Can't change the class variable!
And now the subsequent result:
/Users/erikmikac/PycharmProjects/pythonProject/venv/bin/python/Users/erikmikac/PycharmProjects/pythonProject/main.py Traceback (most recent call last): File "/Users/erikmikac/PycharmProejcts/main.py", line 7 in <module> Dog.Dog.legs = 32 #<—This will break now. Can't change the class variable! File "/Users/erikmikac/PycharmProjects/pythonProject/Dog.py", line 3, in __setattr__ raise ValueError(key) ValueError: legs My dog has 4 legs. Now my dog has 5 legs.
As you can see, it threw a ValueError when attempting to change the class variable. Mutating the instance variable, on the other hand, was fine.
Understanding the difference between a class variable and an instance variable is fundamental. While it may seem nuanced at first, the more you work with data the more apparent it will become when to use which variable. Good luck with your Python journey.