Python Class Variables and Instance Variables

Understanding the difference between Class Var and Instance Var is fundamental to OOP.

Class Var

Given a class Lang, as below

class Lang:
    name = "Python"
    version = "3.8"

    def __init__(self, name, version):
        name = name
        version = version

lang1 = Lang("Java", "8.0")
lang2 = Lang("Javascript", "ES6")
print(lang1.name)
print(lang2.name)

The results will be

Because the vars printed are class variables, Class Var is associated with the Class Lang

Instance Var

Change the code

class Lang:
    name = "Python"
    version = "3.8"

    def __init__(self, name, version):
        self.name = name
        self.version = version

lang1 = Lang("Java", "8.0")
lang2 = Lang("Javascript", "ES6")
print(lang1.name)
print(lang2.name)
print(Lang.name)

Instance Var is associated with a specific Object. In this example, name is not a good practice for Class var.
As name is usually specific with a concrete object.

The lookup order

Go back to the code below

class Lang:
    name = "Python"
    version = "3.8"

    def __init__(self, name, version):
        name = name
        version = version

lang1 = Lang("Java", "8.0")
lang2 = Lang("Javascript", "ES6")
print(lang1.__dict__)
print(Lang.__dict__)

print out the __dict__, lang1 is empty now

Let’s add back self

class Lang:
    name = "Python"
    version = "3.8"

    def __init__(self, name, version):
        self.name = name
        self.version = version
        # below will print out instance var
        print(name)
        print(version)

lang1 = Lang("Java", "8.0")
print(lang1.__dict__)
print(Lang.__dict__)

Now lang1 has proper attributes.

Here’s a Pythonic system to look up variables:

  • Python will start look for variables in the object
  • If the object doesn’t contain the target variable, it will continue search for the variable on the Class level
  • If the target variable is not found on the Class level, it will keep searching from the parent Class level if there’s inheritance

Self

  • self is explicitly needed for instance attributes and methods
  • user don’t need to assign self manually, it’s automatically done by python
  • similar to this in Java
class Lang:
    name = "Python"
    version = "3.8"

    def __init__(self, name, version):
        self.name = name
        self.version = version

    def check_version(self):
        print(self.version)

lang1 = Lang("Java", "8.0")
lang1.check_version()
  • self is the object that invokes the method at the moment, e.g. for lang1.check_version(), self is lang1 in the case above

Access Instance Var and Class Var within Instance Methods

  • instance methods: behavior
  • instance vars: attributes
  • instance methods usually would perform some operations on vars to change the states/results of vars, hence they need to access vars in classes or instances
  • __init__ function is a special type of instance method. It defines and initializes the attributes of an instance
  1. Instance methods to access instance vars, self.varname

  2. Instance methods to access class vars

class Lang:
    count = 0
    name = "class"

    def __init__(self, name, version):
        self.name = name
        self.version = version
        print(self.name)
        # below is not instance var, it's the arg defined in __init__
        print(name)

    def check_version(self):
        print(self.version)

lang1 = Lang("Java", "8.0")

The print out results are misleading here, if we change the arg name to lang, print(name) will report error as name doesn’t exist any more

class Lang:
    count = 0
    name = "class"

    def __init__(self, lang, version):
        self.name = lang
        self.version = version
        print(self.name)
        # below is not instance var, it's the arg defined in __init__
        print(name)

    def check_version(self):
        print(self.version)

lang1 = Lang("Java", "8.0")
  • How to access the class var count?
class Lang:
    count = 0
    name = "class"

    def __init__(self, lang, version):
        self.name = lang
        self.version = version
        print(count)

    def check_version(self):
        print(self.version)

lang1 = Lang("Java", "8.0")

It will still report name error

  • To properly access the class var, the class name is needed
class Lang:
    count = 0
    name = "class"

    def __init__(self, lang, version):
        self.name = lang
        self.version = version
        print(Lang.count)

    def check_version(self):
        print(self.version)

lang1 = Lang("Java", "8.0")
  • Magically self.count is also accessible thanks to the order of looking var: instance then class then parent class
class Lang:
    count = 0
    name = "class"

    def __init__(self, lang, version):
        self.name = lang
        self.version = version
        print(self.count)

    def check_version(self):
        print(self.version)

lang1 = Lang("Java", "8.0")

   Reprint policy


《Python Class Variables and Instance Variables》 by Isaac Zhou is licensed under a Creative Commons Attribution 4.0 International License
  TOC