This page looks best with JavaScript enabled

Python - Variables

 ·   ·  β˜• 8 min read

    Overview of OOP Terminology

    • Class βˆ’ A user-defined prototype for an object that defines a set of attributes that characterize any object of the class. The attributes are data members (class variables and instance variables) and methods, accessed via dot notation.

    • Class variable βˆ’ A variable that is shared by all instances of a class. Class variables are defined within a class but outside any of the class’s methods. Class variables are not used as frequently as instance variables are.

    • Data member βˆ’ A class variable or instance variable that holds data associated with a class and its objects.

    • Function overloading βˆ’ The assignment of more than one behavior to a particular function. The operation performed varies by the types of objects or arguments involved.

    • Instance variable βˆ’ A variable that is defined inside a method and belongs only to the current instance of a class.

    • Inheritance βˆ’ The transfer of the characteristics of a class to other classes that are derived from it.

    • Instance βˆ’ An individual object of a certain class. An object obj that belongs to a class Circle, for example, is an instance of the class Circle.

    • Instantiation βˆ’ The creation of an instance of a class.

    • Method βˆ’ A special kind of function that is defined in a class definition.

    • Object βˆ’ A unique instance of a data structure that is defined by its class. An object comprises both data members (class variables and instance variables) and methods.

    • Operator overloading βˆ’ The assignment of more than one function to a particular operator.

    Define a class

    
    class Dog:
        # Class attribute
        # shared accross all instances and can be changed
        species = "Canis familiaris"
    
        # Constructor (with any optional arguments)
        # Sample Call : obj = className(args)
        def  __init__(self,name,age):
            # instance attributes
            self.name=name
            self.age=age
    
        # Destructor, deletes an object
        # Sample Call : del obj
        def __del__(self):
          class_name = self.__class__.__name__
          print(class_name, "destroyed")
    
        def __new__(cls):
            print ("__new__ magic method is called")
            inst = object.__new__(cls)
            return inst
    
    
        # Instance method
        def description(self):
            return f"{self.name} is {self.age} years old"
    
        def setWeight(self,weight):
            # data hiding with double underscore
            self.__weight=weight
    
        def getWeight(self):
            return self.__weight
    
        def setColor(self,color):
            self._color=color # protected method
    
    
        # Another instance method
        def speak(self, sound):
            return f"{self.name} says {sound}"
    
        # __cmp__ ( self, x )
        # Object comparison
        # Sample Call : cmp(obj, x)
        def __cmp__(self,other):
          return True if self.name==other.name else False
    
        # Overloading Operators
        # a+b
        def __add__(self,other):
            return self.age+other.age
    
    
        # magic/dunder methods
        # Printable string representation 
        # Sample Call : str(obj)
        def __str__(self):
            return f"{self.name} is {self.age} years old"
    
        # Evaluatable string representation
        # Sample Call : repr(obj)
        def __repr__(self):
            return f"{self.name} is {self.age} years old"
    
    
    
    >>> miles = Dog("Miles", 4)
    >>> print(miles)
    'Miles is 4 years old'
    
    

    Child class

    
    class BullDog(Dog):
        # method overriding
        def speak(self, sound="Arf"):
            return f"{self.name} says {sound}"
    
    
    
    
    

    We can use issubclass() or isinstance() functions to check a relationships of two classes and instances.

    • The issubclass(sub, sup) boolean function returns True, if the given subclass sub is indeed a subclass of the superclass sup.

    • The isinstance(obj, Class) boolean function returns True, if obj is an instance of class Class or is an instance of a subclass of Class

    >>> jack = Bulldog("Jack", 3)
    
    >>> isinstance(miles, BullDog)
    False
    
    >>> isinstance(jack, Dog)
    False
    
    
    class Employee:
       empCount = 0
    
       # constructor
       def __init__(self, name, salary):
          self.name = name
          self.salary = salary
          Employee.empCount += 1
    
       def displayCount(self):
         print("Total Employee %d" % Employee.empCount)
    
       def displayEmployee(self):
          print("Name : ", self.name,  ", Salary: ", self.salary)
    
    
    emp1 = Employee("Zara", 2000)
    emp2 = Employee("Manni", 5000)
    emp1.displayEmployee()
    emp2.displayEmployee()
    print("Total Employee %d" % Employee.empCount)
    print(id(emp1)) # prints the id of the object
    

    Output:

    Name :  Zara ,Salary:  2000
    Name :  Manni ,Salary:  5000
    Total Employee 2
    3782888
    

    You can add, remove, or modify attributes of classes and objects at any time βˆ’

    emp1.age = 7  # Add an 'age' attribute.
    emp1.age = 8  # Modify 'age' attribute.
    del emp1.age  # Delete 'age' attribute.
    

    Instead of using the normal statements to access attributes, you can use the following functions βˆ’

    • The getattr(obj, name[, default]) βˆ’ to access the attribute of object.

    • The hasattr(obj,name) βˆ’ to check if an attribute exists or not.

    • The setattr(obj,name,value) βˆ’ to set an attribute. If attribute does not exist, then it would be created.

    • The delattr(obj, name) βˆ’ to delete an attribute.

      hasattr(emp1, ‘age’) # Returns true if ‘age’ attribute exists
      getattr(emp1, ‘age’) # Returns value of ‘age’ attribute
      setattr(emp1, ‘age’, 8) # Set attribute ‘age’ at 8
      delattr(empl, ‘age’) # Delete attribute ‘age’

    Built-In Class Attributes

    Every Python class keeps following built-in attributes and they can be accessed using dot operator like any other attribute βˆ’

    • dict βˆ’ Dictionary containing the class’s namespace.

    • doc βˆ’ Class documentation string or none, if undefined.

    • name βˆ’ Class name.

    • module βˆ’ Module name in which the class is defined. This attribute is “main” in interactive mode.

    • bases βˆ’ A possibly empty tuple containing the base classes, in the order of their occurrence in the base class list.

    For the above class let us try to access all these attributes βˆ’

    print "Employee.__doc__:", Employee.__doc__
    print "Employee.__name__:", Employee.__name__
    print "Employee.__module__:", Employee.__module__
    print "Employee.__bases__:", Employee.__bases__
    print "Employee.__dict__:", Employee.__dict__
    

    To delete an object

    del emp1
    

    classmethod() in Python

    class Person: 
        # create a variable 
        name = "Ohidur"
          
        # create a function 
        def print_name(obj): 
            print("The name is : ", obj.name) 
              
    # create print_name classmethod 
    # before creating this line print_name() 
    # It can be called only with object not with class 
    Person.print_name = classmethod(Person.print_name) 
      
    # now this method can be called as classmethod 
    # print_name() method is called a class method 
    Person.print_name() 
    
    

    The @classmethod and @staticmethod Decorator:

    from datetime import date 
    
    class Person: 
    	def __init__(self, name, age): 
    		self.name = name 
    		self.age = age 
    	
    	# a class method to create a 
    	# Person object by birth year. 
    	@classmethod
    	def fromBirthYear(cls, name, year): 
    		return cls(name, date.today().year - year) 
    	
    	# a static method to check if a 
    	# Person is adult or not. 
    	@staticmethod
    	def isAdult(age): 
    		return age > 18
    
    person1 = Person('mayank', 21) 
    person2 = Person.fromBirthYear('mayank', 1996) 
    
    print (person1.age) 
    print (person2.age) 
    
    # print the result 
    print (Person.isAdult(22)) 
    
    

    Output:

    21
    22
    True
    

    Python property() function

    # Python program to explain property() function 
    
    # Alphabet class 
    class Alphabet: 
    	def __init__(self, value): 
    		self._value = value 
    		
    	# getting the values 
    	def getValue(self): 
    		print('Getting value') 
    		return self._value 
    		
    	# setting the values 
    	def setValue(self, value): 
    		print('Setting value to ' + value) 
    		self._value = value 
    		
    	# deleting the values 
    	def delValue(self): 
    		print('Deleting value') 
    		del self._value 
    	
    	value = property(getValue, setValue, delValue, ) 
    
    # passing the value 
    x = Alphabet('GeeksforGeeks') 
    print(x.value) 
    
    x.value = 'GfG'
    
    del x.value 
    
    

    Output:

    Getting value
    GeeksforGeeks
    Setting value to GfG
    Deleting value
    

    Using @property decorator

    # Python program to explain property() 
    # function using decorator 
    
    class Alphabet: 
    	def __init__(self, value): 
    		self._value = value 
    		
    	# getting the values	 
    	@property
    	def value(self): 
    		print('Getting value') 
    		return self._value 
    		
    	# setting the values	 
    	@value.setter 
    	def value(self, value): 
    		print('Setting value to ' + value) 
    		self._value = value 
    		
    	# deleting the values 
    	@value.deleter 
    	def value(self): 
    		print('Deleting value') 
    		del self._value 
    
    
    # passing the value 
    x = Alphabet('Peter') 
    print(x.value) 
    
    x.value = 'Diesel'
    
    del x.value 
    
    

    Python dataclass

    Data classes are just regular classes that are geared towards storing state, more than contain a lot of logic. Every time you create a class that mostly consists of attributes you made a data class.

    What the dataclasses module does is make it easier to create data classes. It takes care of a lot of boiler plate for you.

    This is especially important when your data class must be hashable; this requires a __hash__ method as well as an __eq__ method. If you add a custom __repr__ method for ease of debugging, that can become quite verbose:

    class InventoryItem:
        '''Class for keeping track of an item in inventory.'''
        name: str
        unit_price: float
        quantity_on_hand: int = 0
    
        def __init__(
                self, 
                name: str, 
                unit_price: float,
                quantity_on_hand: int = 0
            ) -> None:
            self.name = name
            self.unit_price = unit_price
            self.quantity_on_hand = quantity_on_hand
    
        def total_cost(self) -> float:
            return self.unit_price * self.quantity_on_hand
    
        def __repr__(self) -> str:
            return (
                'InventoryItem('
                f'name={self.name!r}, unit_price={self.unit_price!r}, '
                f'quantity_on_hand={self.quantity_on_hand!r})'
    
        def __hash__(self) -> int:
            return hash((self.name, self.unit_price, self.quantity_on_hand))
    
        def __eq__(self, other) -> bool:
            if not isinstance(other, InventoryItem):
                return NotImplemented
            return (
                (self.name, self.unit_price, self.quantity_on_hand) == 
                (other.name, other.unit_price, other.quantity_on_hand))
    

    With dataclasses you can reduce it to:

    from dataclasses import dataclass
        
    @dataclass(unsafe_hash=True)
    class InventoryItem:
        '''Class for keeping track of an item in inventory.'''
        name: str
        unit_price: float
        quantity_on_hand: int = 0
    
        def total_cost(self) -> float:
            return self.unit_price * self.quantity_on_hand
    

    The same class decorator can also generate comparison methods (__lt__, __gt__, etc.) and handle immutability.

    namedtuple classes are also data classes, but are immutable by default (as well as being sequences). dataclasses are much more flexible in this regard, and can easily be structured such that they can fill the same role as a namedtuple class

    The PEP was inspired by the attrs project, which can do even more (including slots, validators, converters, metadata, etc.).

    If you want to use dataclasses module in Python versions < 3.7, then you could install the backported module (requires 3.6) or use the attrs project mentioned above.


    Ohidur Rahman Bappy
    WRITTEN BY
    Ohidur Rahman Bappy
    πŸ“šLearner 🐍 Developer