Python Forum
Distinguishing different types of class attributes
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Distinguishing different types of class attributes
#1
I’m learning Python OOP and I am struggling to understand the difference between defining the two different kinds of class attributes - - static attributes (declared above the dunder __init__ method) as compared to instance attributes (declared beneath and within the scope of the __init__ method).

When I search Google for ‘python difference dunder init method namespace’ the results are split between guides and SO questions/answers explaining either the __init__.py files for Python packaging or the basics on how to instantiate classes in general. Another one here.

I can’t seem to locate a guide which directly addresses the comparison between the different types of the two attributes.

With the above search terms (and some variations), one of the recurring top results is the most useless document of all - - the entry on __init__ objects from the official Python website. I say ‘useless’ because the official doc is practically written in a foreign language (by programmers, for programmers).

What I am looking for is a casual, candid clarification in plain english with practical examples and a description of good potential use cases.

The closest I came to finding an answer to my original question is from SO. In that SO answer, here is a code snippet with its output after execution:

class MyClass(object):
    i = 123
    def __init__(self):
        self.i = 345
  
a = MyClass()
print(MyClass.i)
print(a.i)
Output:
Quote:123
345

Based on this code snippet, my understanding is that the declared first i attribute is universal and applies every time the class is called, whereas the second i also applies at run time, but is just a default container until the program at run time changes it to something else. Is this accurate? Could someone illustrate and better clarify the difference / distinction between the two different types of class attributes? Perhaps also sharing some meaningful use cases for both would be helpful too.

The larger question I seek an answer to is when (and in what context) would a programmer use one of the two possible attribute types instead of the other?

I came up with this question while watching Fred Baptiste’s Python course on OOP.
Reply
#2
The class attributes contain values that are shared by all the instances of the class, so that it is not necessary to repeat the value in every instance, and instance attributes contain values specific to each instance. For example
class Primate:
    pass

class Human(Primate):
    species = 'Homo Sapiens'

    def __init__(self, gender):
        self.gender = gender

Alice = Human('female')
Bob = Human('male')
All the Human instances belong to the same species. It can be stored at class level. On the other hand, every human has its own gender, which is stored at instance level.

If you had subclasses FemaleHuman and MaleHuman, you could store the gender at class level in these subclasses instead of storing it in the instances.

A dangerous feature of Python is that a class attribute can be overriden at instance level. For example
>>> Alice.species
'Homo Sapiens'
>>> Alice.species = 'Gremlin'
>>> Alice.species
'Gremlin'
>>> Bob.species
'Homo Sapiens'
Redefining Alice.species creates an instance attribute that shadows the class attribute from Alice's perspective.
snippsat likes this post
Reply
#3
Drone4fou Wrote:What I am looking for is a casual, candid clarification in plain english with practical examples and a description of good potential use cases.
Look at this guide one of the better ones.
Python Class Attributes: An Overly Thorough Guide
(Feb-21-2022, 02:43 PM)Gribouillis Wrote: A dangerous feature of Python is that a class attribute can be overriden at instance level. For example
To add to this information look under:
So When Should you Use Python Class Attributes?
So class attributes can be tricky and when to use bit is often missing in many tutorials.
Reply
#4
Concise and accurate descriptions are never worthless. I think you don't understand the description from the docs because it doesn't really apply to your question. You are mixing up two topics class/instance variables and __init__().

Class variables exist in the scope of the class and are not associated with any instance. Class variables are declared when the class is constructed (when you run the program or import the module containing the class). Instances of a class can access the class variables, but class variables can be accessed even if there are no instances of the class.
class MyClass:
    value = 42

print(MyClass.value)
x = MyClass()
print(x.value)
Output:
42 42
Scope rules for classes/instances are just like scope rules for globals/functions. Unless steps are taken, assignment sets/creates a variable in the current scope.
class MyClass:
    value = 42  # Creates a class variable

    @classmethod
    def set_class_value(cls, value):
        cls.value = value  # This sets the class variable value

    def set_instance_value(self, value):
        self.value = value  # This sets/creates an instance variable

    def set_class_value_through_instance(self, value):
        self.__class__.value = value  # This is like calling MyClass.value = value

x = MyClass()
print("Initial", MyClass.value, x.value)

x.set_instance_value(3.14)
print("After x.set_instance_value", MyClass.value, x.value)

MyClass.set_class_value(7)
print("After MyClass.set_class_value", MyClass.value, x.value)

x.set_class_value(11)
print("After x.set_class_value", MyClass.value, x.value)

x.set_class_value_through_instance(42)
print("After x.set_class_value_through_instance", MyClass.value, x.value)
Output:
Initial 42 42 After x.set_instance_value 42 3.14 After MyClass.set_class_value 7 3.14 After x.set_class_value 11 3.14 After x.set_class_value_through_instance 42 3.14
Using instance variables that have the same name as class variables is a bad idea and only done here for demonstration purposes.

If you are comfortable with scope rules for Python variables you already know a lot about the scope rules for class and instance variables. If you think of a class as a "module", the class variables behave like global variables. Class variables are declared when the class is constructed. Global variables are defined when the module is "constructed" (executed or imported). Class variables can be seen by all methods in the class. Global variables can be seen by all functions in the module.

Instance variables act like local variables. Instance variables only exist during the lifetime of the instance. Local variables in a function only exist during the lifetime of the function. Assigning a variable in a method (self.value = something) creates an instance variable instead of assigning the class variable. Assigning a variable in a function creates a local variable instead of assigning the global variable. If you want to assign a class variable from inside a method you need to use special syntax (@classmethod decorator or self.__class__). If you want assign a global variable from inside a function you need to use special syntax (global global_variable_name).

__init__() is a mostly unrelated topic. While it is true that a majority of instance variables are assigned in the __init__() method, this is not a defining attribute of __init__(). A class does not need an __init__() method for it to have instance variables. Instance variables can be assigned in any instance method, or even by code external to the class.
class MyClass:
    def setup(self, value=42):
        self.value = value  # This sets/creates an instance variable

x = MyClass()
y = MyClass()
try:
    print(x.value)
except AttributeError as err:
    print(err)

x.setup()
y.value = 3.14
print(x.value, y.value)
Output:
'MyClass' object has no attribute 'value' 42 3.14
The defining characteristic of __init__() is that it is automatically called immediately after an instance is created. If there were no __init__() you would probably create one yourself.
class MyClass:
    def init(self, value=42):
        self.value = value
        return self

x = MyClass().init(3.14)
print(x.value)
Output:
3.14
Reply
#5
I don't use class variables very often.

Here I used class variables to define some constants that are used by instances of the class.
class Message:
    """A class for sending and receiving XXXX style messages.
    My most used methods are:
    send_message - Send message to remote process
    recv_ reply - Get reply from sent message
    recv_message - Read asynchronous message from a remote process
    send_reply - Send reply to remote process
    """
    sentinel = 0xF1F2F3F4  # Value used to mark start and end of a message
    max_params = 8  # Number of parameters in message
    typestr_size = 16  # Size for argument typestring in message
    selector_size = 32  # Size for selector string in message
Here I use a class variable to keep a list of all instances of the class.
class Model(XXXX):
    instances = []

    def __init__(self, parent=None, link=None):
        super().__init__()
        self.parent = parent
        self._link = link
        self.parts = []
        self.instances.append(self)
I can use Model.instances to count how many instances of the class were created, to execute an instance method for each instance, to delete all instances, to keep all instances from being garbage collected.

I've seen code from other Python programmers who use class variables fairly frequently. I remember one poster on this forum who used classes as namespaces. All the variables in his classes were class variables, and all of his classes were singletons.

Class variables are a language feature and it is really up to you to decide when the are useful. Your problem space is not the same as mine. How I write Python is not how you should write Python.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Question [solved] Classes, assign an attributes to a class not to instances.. SpongeB0B 4 934 May-20-2023, 04:08 PM
Last Post: SpongeB0B
  Variable Types in a class nafshar 9 2,463 Oct-07-2022, 07:13 PM
Last Post: deanhystad
  [Solved] Novice question to OOP: can a method of class A access attributes of class B BigMan 1 1,314 Mar-14-2022, 11:21 PM
Last Post: deanhystad
  Calls to Attributes of a Class SKarimi 3 3,394 Apr-22-2021, 04:18 PM
Last Post: SKarimi
  SQL Alchemy dynamic class - declarative_base losing attributes mrdominikku 4 3,733 Jan-10-2020, 06:46 PM
Last Post: mrdominikku
  OpenCV - Distinguishing between three icons kainev 2 1,965 Jul-30-2019, 11:57 PM
Last Post: kainev
  how to add class instance attributes from list 999masks 2 2,723 Jul-22-2019, 07:59 AM
Last Post: 999masks
  Is it possible to loop through class attributes via string? 04chiak 3 9,782 Feb-04-2018, 09:29 PM
Last Post: 04chiak
  Class Instances overriding class members and attributes. Leaf 7 6,932 Nov-29-2017, 06:08 AM
Last Post: Leaf
  Class Attributes Inheritance Harry_Potter 3 3,841 Nov-16-2017, 07:01 PM
Last Post: snippsat

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020