What is class attribute in python

Python Attributes: Class vs. Instance Explained

Learn how to distinguish between the two scopes of Python attributes, class vs instance, and how to use them.

Ahmed El Bir is a data engineer for the fintech company FINAXYS. He has nearly 10 years of experience in technology, including experience as a tech lead in Python and big data for Capgemini, before joining FINAXYS in 2020.

Two pythons with different attributes such as color.

As an object-oriented language, Python provides two scopes for attributes: class attributes and instance attributes. Python class attributes are variables of a class that are shared between all of its instances. They differ from instance attributes in that instance attributes are owned by one specific instance of the class and are not shared between instances. While the instance attribute in Python has exactly the same characteristics and definition as other object-oriented languages, the class attribute is often mistakenly considered to be the exact equivalent of the static attribute in Java or C++. Class attributes in Python and static attributes in Java or C++ have a lot in common, but they have several behavioral differences that I will highlight in this article.

Class Attribute vs. Instance Attribute

  • An instance attribute is a Python variable belonging to one, and only one, object. This variable is only accessible in the scope of this object, and it’s defined inside the constructor function, __init__(self. ) of the class.
  • A class attribute is a Python variable that belongs to a class rather than a particular object. It’s shared between all the objects of this class and is defined outside the constructor function, __init__(self. ) , of the class.
Читайте также:  Вывод наибольшего числа python

The below ExampleClass is a basic Python class with two attributes: class_attr and instance_attr .

class ExampleClass(object): class_attr = 0 def __init__(self, instance_attr): self.instance_attr = instance_attr
  • instance_attr is an instance attribute defined inside the constructor.
  • class_attr is a class attribute defined outside the constructor.

The instance_attr is only accessible from the scope of an object. The class attribute ( class_attr ) is accessible as both a property of the class and as a property of objects, as it’s shared between all of them.

if __name__ == '__main__': foo = ExampleClass(1) bar = ExampleClass(2) # print the instance attribute of the object foo print (foo.istance_attr) #1 #print the instance attribute of the object var print (bar.instance_attr) #2 #print the class attribute of the class ExampleClass as a property of the class itself print (ExampleClass.class_attr) #0 #print the classattribute of the class as a proporty of the objects foo,bar print (bar.class_attr) #0 print (foo.class_attr) #0 # try to print instance attribute as a class property print (ExampleClass.instance_attr) #AttributeError: type object 'ExampleClass' has no attribute 'instance_attr'

Notice that the class attribute can be accessed as a class property and as an instance property, however, accessing an instance attribute as a class property raises an AttributeError .

Python Class Attribute: Namespaces

Behind the scenes, it’s a game of namespaces. If you’ve already read the Zen of Python , the last line states: “Namespaces are one honking great idea — let’s do more of those!” So what is a namespace?

In Python, a namespace is a mapping between objects and names. To keep it simple, let’s say it’s a Python dictionary that represents a key to the name of the object and its value as a value. Different namespaces can coexist with the property while the names within them are independent.

Python classes and objects have different namespaces. For our example, we have ExampleClass.__dict__ as a namespace for our class, and foo.__dict__(bar.__dict__) as a namespace for our object foo(bar) .

if __name__ = '__main__': foo = ExampleClass(1) bar = ExampleClass(2) print str(ExampleClass.__dict__) #, '__weakref__': , '__doc__': None, '__init__': > print str(foo.__dict__) # print str(bar.__dict__) #

When you access an attribute (instance or class attribute) as a property of an object using the dot convention, it searches first in the namespace of that object for that attribute name. If it’s found, it returns the value. Otherwise, it searches in the namespace of the class. If nothing is found there, it raises an AttributeError . The object namespace is before the class namespace.

If we find, in one class, both an instance attribute and a class attribute with the same name, the access to that name from your object will get you the value in the object namespace. Below is a simplified version of the lookup function .

def instlookup(inst, name): ## simplified algorithm. if inst.__dict__.has_key(name): return inst.__dict__[name] else: return inst.__class__.__dict__[name]

When you access an attribute as a class property, it searches directly in the class namespace for the name of that attribute. If it’s found, it returns the value. Otherwise, it raises an AttributeError .

Class Attributes Mutate Into Instance Attributes

It might seem weird, but class attributes do mutate to become instance attributes. Let’s consider the following scenario, and then comment on it together.

if __name__ = '__main__': foo = ExampleClass(1) bar = ExampleClass(2) #print the class attribute as a porperty of a foo print foo.class_attr #0 #modify the class attribute as a foo property foo.class_attr = 5 print foo.class_attr #5 #print the class attribute as a porperty of a bar print bar.class_attr # 0 #oups . 

The class_attr is shared between all the objects of the class. However, when we change the value from the foo object, this change is not visible from the bar object, which still has the old value, 0 , rather than the new value, 5 . Let’s check our namespaces and try to understand what’s happening.

if __name__ = '__main__': foo = ExampleClass(1) bar = ExampleClass(2) print str(foo.__dict__) # the namespace of the foo object had only his instance attribute print foo.class_attr #0 foo.class_attr = 5 print str(foo.__dict__) ''' once the affectation is done on the class attribute from the object foo , it is added as an instance attribute in his namespace ''' 

​The affectation added a new instance attribute to the object foo , and only to that object, which is why in the previous example the object bar kept printing the class attribute.

With immutable objects, this behavior is always the same. However, with mutable objects like lists , for example, it’s not always the case and depends on how you modify your class attribute.

Let’s change our previous class to have a list as a class attribute.

class ExampleClass(object): class_attr = [] def __init__(self, instance_attr): self.instance_attr = instance_attr

We modify that list as a property of the object foo by appending a new element to it.

if __name__ = '__main__': foo = ExampleClass(1) bar = ExampleClass(2) #print the class attribute as a porperty of a foo print foo.class_attr # [] #modify the class attribute as a foo property foo.class_attr.append(0) print foo.class_attr #[0] #print the class attribute as a porperty of a bar print bar.class_attr # [0] 

​ When a mutable class attribute is modified by an object, it does not mutate into an instance attribute for that object. It stays shared between all the objects of the class with the new elements appended to it.

However, if you attach a new list to that attribute ( foo.class_attr = list(«foo») ), you’ll get the same behavior as the immutable objects.

if __name__ = '__main__': foo = ExampleClass(1) bar = ExampleClass(2) #print the class attribute as a porperty of a foo print foo.class_attr # [] #modify the class attribute as a foo property foo.class_attr = list("example") print foo.class_attr #[e,x,a,m,p,l,e] #print the class attribute as a porperty of a bar print bar.class_attr # [] 

You can compare the namespaces on your own as proof of the previous behavior.

The takeaway is that Python class attributes may be useful in different cases, however, they must be used with caution in order to avoid unexpected behaviors.

Источник

Python Attributes – Class and Instance Attribute Examples

Ihechikara Vincent Abba

Ihechikara Vincent Abba

Python Attributes – Class and Instance Attribute Examples

When creating a class in Python, you’ll usually create attributes that may be shared across every object of a class or attributes that will be unique to each object of the class.

In this article, we’ll see the difference between class attributes and instance attributes in Python with examples.

Before we do that, let’s see how to create a class in Python.

How to Create a Class in Python

To create a class in Python, we use the class keyword followed by the name of the class. Here is an example:

class Student: name = "Jane" course = "JavaScript"

In the code above, we created a class called Student with a name and course property. Now let’s create new objects from this class.

class Student: name = "Jane" course = "JavaScript" Student1 = Student() print(Student1.name) # Jane

We’ve created a new object called Student1 from the Student class.

When we printed Student1.name , we got «Jane» printed to the console. Recall that the value of Jane was stored in a variable in the original class created.

This name and course variables are actually class attributes. We’ll see more examples in the next section to help you understand better.

Class and Instance Attributes in Python

To give a basic definition of both terms, class attributes are class variables that are inherited by every object of a class. The value of class attributes remain the same for every new object.

Like you will see in the examples in this section, class attributes are defined outside the __init__() function.

On the other hand, instance attributes, which are defined in the __init__() function, are class variables that allow us to define different values for each object of a class.

class Student: school = "freeCodeCamp.org" def __init__(self, name, course): self.name = name self.course = course Student1 = Student("Jane", "JavaScript") Student2 = Student("John", "Python") print(Student1.name) # Jane print(Student2.name) # John 

In the code above, we created a variable in the Student class called school .

We created two more variables but in the __init__() function – name and course – which we initialized using the self parameter.

The first parameter in an __init__() function is used to initialize other parameters when creating variables in the function. You can call it whatever you want – by convention, self is mostly used.

The school variable acts as a class attribute while name and course are instance attributes. Let’s break the example above down to explain instance attributes.

Student1 = Student("Jane", "JavaScript") Student2 = Student("John", "Python") print(Student1.name) # Jane print(Student2.name) # John

We created two objects from the Student class – Student1 and Student2 . Each of these objects, by default, will have all the variables created in the class. But each object is able to have its own name and course variable because they were created in the __init__() function.

Now let’s print the school variable for each object and see what happens.

print(Student1.school) # freeCodeCamp.org print(Student2.school) # freeCodeCamp.org

Both gave us the same value because the school variable is a class attribute.

Conclusion

In this article, we saw how to create a class in Python and the differences between class and instance attributes.

In summary, class attributes remain the same for every object and are defined outside the __init__() function. Instance attributes are somewhat dynamic because they can have different values in each object.

Instance attributes are defined in the __init__() function.

Источник

Оцените статью