Instance variables vs. class variables in Python

103,197

Solution 1

If you have only one instance anyway, it's best to make all variables per-instance, simply because they will be accessed (a little bit) faster (one less level of "lookup" due to the "inheritance" from class to instance), and there are no downsides to weigh against this small advantage.

Solution 2

Further echoing Mike's and Alex's advice and adding my own color...

Using instance attributes are the typical... the more idiomatic Python. Class attributes are not used used as much, since their use cases are specific. The same is true for static and class methods vs. "normal" methods. They're special constructs addressing specific use cases, else it's code created by an aberrant programmer wanting to show off they know some obscure corner of Python programming.

Alex mentions in his reply that access will be (a little bit) faster due to one less level of lookup... let me further clarify for those who don't know about how this works yet. It is very similar to variable access -- the search order of which is:

  1. locals
  2. nonlocals
  3. globals
  4. built-ins

For attribute access, the order is:

  1. instance
  2. class
  3. base classes as determined by the MRO (method resolution order)

Both techniques work in an "inside-out" manner, meaning the most local objects are checked first, then outer layers are checked in succession.

In your example above, let's say you're looking up the path attribute. When it encounters a reference like "self.path", Python will look at the instance attributes first for a match. When that fails, it checks the class from which the object was instantiated from. Finally, it will search the base classes. As Alex stated, if your attribute is found in the instance, it doesn't need to look elsewhere, hence your little bit of time savings.

However, if you insist on class attributes, you need that extra lookup. Or, your other alternative is to refer to the object via the class instead of the instance, e.g., MyController.path instead of self.path. That's a direct lookup which will get around the deferred lookup, but as alex mentions below, it's a global variable, so you lose that bit that you thought you were going to save (unless you create a local reference to the [global] class name).

The bottom-line is that you should use instance attributes most of the time. However, there will be occasions where a class attribute is the right tool for the job. Code using both at the same time will require the most diligence, because using self will only get you the instance attribute object and shadows access to the class attribute of the same name. In this case, you must use access the attribute by the class name in order to reference it.

Solution 3

When in doubt, you probably want an instance attribute.

Class attributes are best reserved for special cases where they make sense. The only very-common use case is methods. It isn't uncommon to use class attributes for read-only constants that instances need to know (though the only benefit to this is if you also want access from outside the class), but you should certainly be cautious about storing any state in them, which is seldom what you want. Even if you will only have one instance, you should write the class like you would any other, which usually means using instance attributes.

Solution 4

Same question at Performance of accessing class variables in Python - the code here adapted from @Edward Loper

Local Variables are the fastest to access, pretty much tied with Module Variables, followed by Class Variables, followed by Instance Variables.

There are 4 scopes you can access variables from:

  1. Instance Variables (self.varname)
  2. Class Variables (Classname.varname)
  3. Module Variables (VARNAME)
  4. Local Variables (varname)

The test:

import timeit

setup='''
XGLOBAL= 5
class A:
    xclass = 5
    def __init__(self):
        self.xinstance = 5
    def f1(self):
        xlocal = 5
        x = self.xinstance
    def f2(self):
        xlocal = 5
        x = A.xclass
    def f3(self):
        xlocal = 5
        x = XGLOBAL
    def f4(self):
        xlocal = 5
        x = xlocal
a = A()
'''
print('access via instance variable: %.3f' % timeit.timeit('a.f1()', setup=setup, number=300000000) )
print('access via class variable: %.3f' % timeit.timeit('a.f2()', setup=setup, number=300000000) )
print('access via module variable: %.3f' % timeit.timeit('a.f3()', setup=setup, number=300000000) )
print('access via local variable: %.3f' % timeit.timeit('a.f4()', setup=setup, number=300000000) )

The result:

access via instance variable: 93.456
access via class variable: 82.169
access via module variable: 72.634
access via local variable: 72.199
Share:
103,197
deamon
Author by

deamon

Updated on July 09, 2022

Comments

  • deamon
    deamon almost 2 years

    I have Python classes, of which I need only one instance at runtime, so it would be sufficient to have the attributes only once per class and not per instance. If there would be more than one instance (which won't happen), all instance should have the same configuration. I wonder which of the following options would be better or more "idiomatic" Python.

    Class variables:

    class MyController(Controller):
    
      path = "something/"
      children = [AController, BController]
    
      def action(self, request):
        pass
    

    Instance variables:

    class MyController(Controller):
    
      def __init__(self):
        self.path = "something/"
        self.children = [AController, BController]
    
      def action(self, request):
        pass
    
    • Gabriel Staples
      Gabriel Staples over 7 years
      After reading this question and seeing the answer, one of my first questions was, "So how do I access class variables?" --that's because up to this point I've only used instance variables. In answer to my own question, you do it via the class name itself, though technically you can do it via an instance too. Here's a link to read for anyone else with the same question: stackoverflow.com/a/3434596/4561887
  • deamon
    deamon about 14 years
    The class variables are a kind of read-only constants. If Python let me define constants, I would have written it as constants.
  • Devin Jeanpierre
    Devin Jeanpierre about 14 years
    Never heard of the Borg pattern? Only having one instance was the wrong way to have it in the first place.
  • Mike Graham
    Mike Graham about 14 years
    @deamon, I am slightly more likely to put my constants completely outside of a class definitions and name them in all caps. Putting them inside the class is fine too. Making them instance attributes won't hurt anything, but might be a bit odd. I don't think this is an issue where the community gets behind one of the options too much.
  • Alex Martelli
    Alex Martelli about 14 years
    @Devin, yep, I've heard of the Borg pattern, since I'm the one who introduced it (in 2001, cfr code.activestate.com/recipes/… ;-). But there's nothing wrong, in simple cases, with simply having a single instance with no enforcement.
  • Alex Martelli
    Alex Martelli about 14 years
    @wescpy, but MyController is looked up in the globals, so the total cost is higher than self.path where path is an instance variable (since self is local to the method == super-fast lookup).
  • wescpy
    wescpy about 14 years
    ah, true. good catch. i guess the only workaround is to create a local reference... at this point, it's not really worth it.
  • Dennis
    Dennis over 10 years
    @MikeGraham FWIW, Google's Python Style Guide suggests to avoid global variables in favor of class variables. There are exceptions though.
  • Alex Martelli
    Alex Martelli over 8 years
    @user1767754, easy to make them yourself with python -mtimeit -- but having just done so in python3.4 I note that accessing an int class variable is actually about 5 to 11 nanoseconds faster than the same as instance variable on my old workstation -- not sure what codepath makes it so.
  • colidyre
    colidyre almost 6 years
    Here is a new link to Google's Python Style Guide. Now there is simply written: avoid global variables and their definition is, that global variables are also variables that are declared as class attributes. However, Python's own style guide (PEP-8) should be the first place to go for questions of this kind. Then your own mind should be the tool of choice (of course you can also get ideas from Google, for example).