Open In App

Understanding Python Dataclasses

DataClasses has been added in a recent addition in python 3.7 as a utility tool for storing data. DataClasses provides a decorator and functions for automatically adding generated special methods such as __init__() , __repr__() and __eq__() to user-defined classes.

DataClass in Python

DataClasses are like normal classes in Python, but they have some basic functions like instantiation, comparing, and printing the classes already implemented.



Installing the DataClasses module:

pip install dataclasses

The syntax of the dataclass is:



Syntax: @dataclasses.dataclass(*, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)

Parameters:

  • init: If true  __init__() method will be generated
  • repr: If true  __repr__() method will be generated
  • eq: If true  __eq__() method will be generated
  • order: If true  __lt__(), __le__(), __gt__(), and __ge__() methods will be generated.
  • unsafe_hash: If False __hash__() method is generated according to how eq and frozen are set
  • frozen: If true assigning to fields will generate an exception.

DataClass module provides a handy way to make classes less wordy. Let us see the traditional approach without using DataClass.




# creating a employee class
class employee:
     
    # init method or constructor
    def __init__(self, name, emp_id, age, city):
         
        # Instance Variable
        self.name = name
        self.emp_id = emp_id
        self.age = age
        self.city = city
     
    # magic function to return class object
    def __repr__(self):
        return ("employee (name={}, emp_id={}, age={}, city={} )"
                .format(self.name, self.emp_id, self.age, self.city))
     
    # magic function to return boolean
    def __eq__(self, check):
        return ((self.name, self.emp_id, self.age, self.city) ==
                ((check.name, check.emp_id, check.age, check.city)))
 
 
# initialization the object
emp1 = employee("Satyam", "ksatyam858", 21, 'Patna')
emp2 = employee("Anurag", "au23", 28, 'Delhi')
emp3 = employee("Satyam", "ksatyam858", 21, 'Patna')
 
print("employee object are :")
print(emp1)
print(emp2)
print(emp3)
 
# printing new line
print()
 
# referring two object to check equality
print("Data in emp1 and emp2 are same? ", emp1 == emp2)
print("Data in emp1 and emp3 are same? ", emp1 == emp3)

Output
employee object are :
employee (name=Satyam, emp_id=ksatyam858, age=21, city=Patna )
employee (name=Anurag, emp_id=au23, age=28, city=Delhi )
employee (name=Satyam, emp_id=ksatyam858, age=21, city=Patna )

Data in emp1 and emp2 are same?  False
Data in emp1 and emp3 are same?  True

In the above code the biggest problem in passing the argument in __init__, __repr__, and __eq__. Each time it has to copy its properties and return the object. It is a good way of dealing with a small amount of data but supposes we have work with large data. It makes your code more complicated. So, that why DataClass will implement to make your code easier and handy.

Here are the same example, implemented in Python DataClasses




# A basic Data Class
# importing dataclass module
from dataclasses import dataclass
 
# A class for holding an employees content
@dataclass
class employee:
 
    # Attributes Declaration
    # using Type Hints
    name: str
    emp_id: str
    age: int
    city: str
 
 
emp1 = employee("Satyam", "ksatyam858", 21, 'Patna')
emp2 = employee("Anurag", "au23", 28, 'Delhi')
emp3 = employee("Satyam", "ksatyam858", 21, 'Patna')
 
print("employee object are :")
print(emp1)
print(emp2)
print(emp3)
 
# printing new line
print()
 
# referring two object to check equality
print("Data in emp1 and emp2 are same? ", emp1 == emp2)
print("Data in emp1 and emp3 are same? ", emp1 == emp3)

Output: 

employee object are : 
employee(name=’Satyam’, emp_id=’ksatyam858′, age=21, city=’Patna’) 
employee(name=’Anurag’, emp_id=’au23′, age=28, city=’Delhi’) 
employee(name=’Satyam’, emp_id=’ksatyam858′, age=21, city=’Patna’)
Data in emp1 and emp2 are same?  False 
Data in emp1 and emp3 are same?  True 
 

In the above code, we don’t need to write a code for __init__, __repr__, and __eq__ function. 

dataclasses.Field()

The field() objects describe each defined field.  

Syntax: dataclasses.field(*, default=MISSING, default_factory=MISSING, repr=True, hash=None, init=True, compare=True, metadata=None)

Parameters:

  • default
  • default_factory
  • init
  • repr
  • hash
  • compare
  • metadata

Example: Demonstration of how to view the fields of a dataclass object. 




from dataclasses import dataclass
 
# A class for holding an employees content
@dataclass
class employee:
 
    # Attributes Declaration
    # using Type Hints
    name: str
    emp_id: str
    age: int
    city: str
 
 
# object of the class
emp = employee("Satyam", "ksatyam858", 21, 'Patna')
 
emp.__dataclass_fields__

Output:

Explanation of the parameters :




# default field example
from dataclasses import dataclass, field
 
 
# A class for holding an employees content
@dataclass
class employee:
 
    # Attributes Declaration
    # using Type Hints
    name: str
    emp_id: str
    age: int
       
    # default field set
    # city : str = "patna"
    city: str = field(default="patna")
 
 
emp = employee("Satyam", "ksatyam858", 21)
print(emp)

Output:

employee(name=’Satyam’, emp_id=’ksatyam858′, age=21, city=’patna’) 
 




# default factory example
from dataclasses import dataclass, field
 
 
def get_emp_id():
    id = 2345
    return id
 
# A class for holding an employees content
@dataclass
class employee:
 
    # Attributes Declaration
    # using Type Hints
    name: str
    age: int
       
    # default factory field
    emp_id: str = field(default_factory=get_emp_id)
    city: str = field(default="patna")
 
 
# object of dataclass
emp = employee("Satyam", 21)
print(emp)

Output:

employee(name=’Satyam’, age=21, emp_id=2345, city=’patna’) 
 




# init field example
from dataclasses import dataclass, field
 
# A class for holding an employees content
@dataclass
class employee:
 
    # Attributes Declaration
    # using Type Hints
    name: str
    age: int
       
    # init field
    emp_id: str
    city: str = field(init=False, default="patna")
 
 
# object of dataclass
emp = employee("Satyam", "ksatyam858", 21)
print(emp)

Output:

employee(name=’Satyam’, age=’ksatyam858′, emp_id=21, city=’patna’) 
 




# repr field
from dataclasses import dataclass, field
 
# A class for holding an employees content
@dataclass
class employee:
 
    # Attributes Declaration
    # using Type Hints
    name: str
    age: int
    emp_id: str
    city: str = field(init=False, default="patna", repr=True)
 
emp = employee("Satyam", 21, "ksatyam858"),
print(emp)

Output: 

employee(name=’Satyam’, age=21, emp_id=’ksatyam858′, city=’patna’) 
 

If repr is false then: 




city: str = field(init=False, default="patna", repr=False)
 
emp = employee("Satyam", 21, "ksatyam858"),
emp

Output:

employee(name='Satyam', age=21, emp_id='ksatyam858')




# hash
from dataclasses import dataclass, field
 
# A class for holding an employees content
@dataclass(unsafe_hash=True)
class employee:
 
    # Attributes Declaration
    # using Type Hints
    name: str
    age: int
    emp_id: str = field(default_factory=get_emp_id)
    city: str = field(init=False, default="patna", repr=True, hash=True)
 
emp = employee("Satyam", "ksatyam858", 21)
hash(emp)

Output:

28166796391311520

If false then it will not consider these field.




city: str = field(init=False, default="patna", repr=True, hash=False)
 
# object of the class
emp = employee("Satyam", "ksatyam858", 21)
hash(emp)

Output:

6124029366977666702




# hash
from dataclasses import dataclass, field
 
# A class for holding an employees content
@dataclass(unsafe_hash=True)
class employee:
 
    # Attributes Declaration
    # using Type Hints
    name: str
    age: int
    emp_id: str
    city: str = field(init=False, default="patna",
                      repr=True, hash=False, compare=True)
 
 
emp1 = employee("Satyam", "ksatyam858", 21)
emp2 = employee("Kumar", "satyam.10151", 22)
emp1 == emp2

Output:

False




# hash
from dataclasses import dataclass, field
 
# A class for holding an employees content
@dataclass(unsafe_hash=True)
class employee:
 
    # Attributes Declaration
    # using Type Hints
    name: str
    age: int
    emp_id: str
    city: str = field(init=False, default="patna", repr=True,
                      metadata={'format': 'State'})
 
emp = employee("Satyam", "ksatyam858", 21)
emp.__dataclass_fields__['city'].metadata['format']

Post-init processing

 While creating object __post_init__() method call automatically. __init__() code will call a method named __post_init__().

Example: In an employee dataclass, if we want to check employee age, then we can define into the __post_init__() method.




# A basic Data Class
# importing dataclass module
from dataclasses import dataclass, field
 
 
# A class for holding an employees content
@dataclass
class employee:
 
    # Attributes Declaration
    # using Type Hints
    name: str
    emp_id: str
    age: int
    city: str
 
    # post init function
    def __post_init__(self):
        if self.age >= 30:
            self.check_age = True
        else:
            self.check_age = False
 
 
emp = employee("Satyam", "ksatyam858", 21, 'Patna')
emp.check_age

Output:

False

DataClass Inheritance

Inheritance enables us to define a class that takes all the functionality from a parent class.

Example: Child class inherits the properties of the parent class.




# A basic Data Class
# importing dataclass module
from dataclasses import dataclass, field
 
 
# parent class
@dataclass
class Staff:
    name: str
    emp_id: str
    age: int
 
# child class
@dataclass
class employee(Staff):
    salary: int
 
 
emp = employee("Satyam", "ksatyam858", 21, 60000)
emp

Output:

employee(name='Satyam', emp_id='ksatyam858', age=21, salary=60000)

Article Tags :