Python Class

 

Python: Class and Behavior

Python is a completely object-oriented language. You have been working with classes and objects right from the beginning of these tutorials. Every element in a Python program is an object of a class. A number, string, list, dictionary, etc., used in a program is an object of a corresponding built-in class. You can retrieve the class name of variables or objects using the "type()" method, as shown below.

Example: Python Built-in Classes

```

>>> num=20
>>> type(num)
<class 'int'>            
>>> s="Python"
>>> type(s) 
<class 'str'>

```

- Defining a Class

A class in Python can be defined using the "class" keyword.

```

class <ClassName>:
    <statement1>
    <statement2>
    .
    .
    <statementN>

```

1. Class Attributes

2. Constructor

3. Instance Attributes

4. Properties

5. Class Methods

A class can also be defined without any members. The following example defines an empty class using the "pass" keyword

Example: Define Python Class

```

class Student:
    pass

```

Class instantiation uses function notation. To create an object of the class, just call a class like a parameter-less function that returns a new object of the class, as shown below.

Example: Creating an Object of a Class

```

std = Student()

```

Above, Student() returns an object of the Student class, which is assigned to a local variable std. The Student class is an empty class because it does not contain any members.


- Class Attributes

Class attributes are the variables defined directly in the class that are shared by all objects of the class. Class attributes can be accessed using the class name as well as using the objects.

Example: Define Python Class

```

class Student:
    schoolName = 'XYZ School' 

```

Above, the schoolName is a class attribute defined inside a class. The value of the schoolName will remain the same for all the objects unless modified explicitly.

Example: Use Define Python Class

```

>>> Student.schoolName
'XYZ School' 
>>> std = Student()
>>> std.schoolName
'XYZ School' 

```

As you can see, a class attribute is accessed by Student.schoolName as well as std.schoolName. Changing the value of class attribute using the class name would change it across all instances. However, changing class attribute value using instance will not reflect to other instances or class.

Example: Explain Define Python Class

```

>>> Student.schoolName = 'ABC School' # change attribute value using class name
>>> std = Student()
>>> std.schoolName
'ABC School'   # value changed for all instances
>>> std.schoolName = 'My School'  # changing instance's attribute
>>> std.schoolName
'My School' 
>>> Student.schoolName # instance level change not reflects to class attribute
'ABC School' 
>>> std2 = Student()
>>> std2.schoolName
'ABC School' 

```

The following example demonstrates the use of class attribute count.

Example: Student.py

```

class Student:
    count = 0
    def __init__(self):
        Student.count += 1                

```

In the above example, count is an attribute in the Student class. Whenever a new object is created, the value of count is incremented by 1. You can now access the count attribute after creating the objects, as shown below.

Example:

```

>>> std1=Student()
>>> Student.count
1
>>> std2 = Student()
>>> Student.count
2

```


- Constructor

In Python, the constructor method is invoked automatically whenever a new object of a class is instantiated, same as constructors in C# or Java. The constructor must have a special name __init__() and a special parameter called self.

 Note:

The first parameter of each method in a class must be the self , which refers to the calling object. However, you can give any name to the first parameter, not necessarily self.

Example: Constructor

```

class Student:
    def __init__(self): # constructor method
        print('Constructor invoked')

```

Now, whenever you create an object of the Student class, the __init__() constructor method will be called, as shown below.

```

>>>s1 = Student()
Constructor invoked
>>>s2 = Student()
Constructor invoked

```

The constructor in Python is used to define the attributes of an instance and assign values to them.


- Instance Attributes

Instance attributes are attributes or properties attached to an instance of a class. Instance attributes are defined in the constructor.


The following example defines instance attributes name and age in the constructor.

Example: Instance Attributes

```

class Student:
    schoolName = 'XYZ School' # class attribute

    def __init__(self): # constructor
        self.name = '' # instance attribute
        self.age = 0 # instance attribute

```

An instance attribute can be accessed using dot notation: [instance name].[attribute name], as shown below.

Example:

```

>>> std = Student()
>>> std.name
''
>>> std.age
0

```

You can set the value of attributes using the dot notation, as shown below.

Example:

```

>>> std = Student()
>>> std.name = "Bill" # assign value to instance attribute
>>> std.age=25        # assign value to instance attribute
>>> std.name          # access instance attribute value
Bill
>>> std.age           # access value to instance attribute
25

```

You can specify the values of instance attributes through the constructor. The following constructor includes the name and age parameters, other than the self parameter.

Example: Setting Attribute Values

```

class Student:
    def __init__(self, name, age): 
        self.name = name
        self.age = age

```

Now, you can specify the values while creating an instance, as shown below.

Example: Passing Instance Attribute Values in Constructor

```

>>> std = Student('Bill',25)
>>> std.name
'Bill'
>>> std.age
25

```

 Note:

You don't have to specify the value of the self parameter. It will be assigned internally in Python.

You can also set default values to the instance attributes. The following code sets the default values of the constructor parameters. So, if the values are not provided when creating an object, the values will be assigned latter.

Example: Setting Default Values of Attributes

```

class Student:
    def __init__(self, name="Guest", age=25)
        self.name=name
        self.age=age

```

Now, you can create an object with default values, as shown below.

Example: Instance Attribute Default Value

```

>>> std = Student()
>>> std.name
'Guest'
>>> std.age
25

```


- Class Properties

In Python, a property in the class can be defined using the property() function.


The property() method in Python provides an interface to instance attributes. It encapsulates instance attributes and provides a property, same as Java and C#.


The property() method takes the get, set and delete methods as arguments and returns an object of the property class.


The following example demonstrates how to create a property in Python using the property() function.

Example: property()

```

class Student:
    def __init__(self):
        self.__name=''
    def setname(self, name):
        print('setname() called')
        self.__name=name
    def getname(self):
        print('getname() called')
        return self.__name
    name=property(getname, setname)

```

In the above example, property(getname, setname) returns the property object and assigns it to name. Thus, the name property hides the "private instance attribute" __name. The name property is accessed directly, but internally it will invoke the getname() or setname() method, as shown below.

Example: property()

```

>>> std = Student()
>>> std.name="Steve"
setname() called
>>> std.name
getname() called
'Steve'

```

It is recommended to use the property decorator instead of the property() method. 
(See bottom from more info in @property decorator)


- Class Methods

You can define as many methods as you want in a class using the def keyword. Each method must have the first parameter, generally named as self, which refers to the calling instance.

Example: Class Method

```

class Student:
    def displayInfo(self): # class method
        print('Student Information')

```

Self is just a conventional name for the first argument of a method in the class. A method defined as mymethod(self, a, b) should be called as x.mymethod(a, b) for the object x of the class.

The above class method can be called as a normal function, as shown below.

Example: Class Method

```

>>> std = Student()
>>> std.displayInfo()
'Student Information'

```

The first parameter of the method need not be named self. You can give any name that refers to the instance of the calling method. The following displayInfo() method names the first parameter as obj instead of self and that works perfectly fine.

Example: Class Method

```

class Student:
    def displayInfo(obj): # class method
        print('Student Information')

```

Defining a method in the class without the self parameter would raise an exception when calling a method.

Example: Class Method

```

class Student:
    def displayInfo(): # method without self parameter
        print('Student Information')

```


```

>>> std = Student()
>>> std.displayInfo()
Traceback (most recent call last):
std.displayInfo()
TypeError: displayInfo() takes 0 positional arguments but 1 was given

```

The method can access instance attributes using the self parameter.

Example: Class Method

```

class Student:
    def __init__(self, name, age): 
        self.name = name 
        self.age = age 
    def displayInfo(self): # class method
        print('Student Name: ', self.name,', Age: ', self.age)

```

You can now invoke the method, as shown below.

Example: Calling a Method

```

>>> std = Student('Steve', 25)
>>> std.displayInfo()
Student Name: Steve , Age: 25 

```


- Deleting Attribute, Object, Class

You can delete attributes, objects, or the class itself, using the del keyword, as shown below.

Example: Delete Attribute, Object, Class

```

>>> std = Student('Steve', 25)
>>> del std.name # deleting attribute
>>> std.name
Traceback (most recent call last):
File "<pyshell#42>", line 1, in <module>
std.name
AttributeError: 'Student' object has no attribute 'name'
>>> del std  # deleting object
>>> std.name  
Traceback (most recent call last):
File "<pyshell#42>", line 1, in <module>
std.name
NameError: name 'std' is not defined
>>> del Student  # deleting class
>>> std = Student('Steve', 25)
Traceback (most recent call last):
File "<pyshell#42>", line 1, in <module>
std = Student()
NameError: name 'Student' is not defined

```


- Python Static method

In this quick post, we will learn how to create and use a Python static method. We will also have a look at what advantages and disadvantages static methods offer as compared to the instance methods. Let’s get started.

What is a static method?

Static methods in Python are extremely similar to python class level methods, the difference being that a static method is bound to a class rather than the objects for that class.


This means that a static method can be called without an object for that class. This also means that static methods cannot modify the state of an object as they are not bound to it. Let’s see how we can create static methods in Python.


Creating python static methods

Python Static methods can be created in two ways. Let’s see each of the ways here:


Using staticmethod()

Let’s directly jump to sample code snippet on how to use the staticmethod() approach:

```

class Calculator:

    def addNumbers(x, y):

        return x + y


# create addNumbers static method

>>Calculator.addNumbers = staticmethod(Calculator.addNumbers)

>>print('Product:', Calculator.addNumbers(15, 110))

```

Note that we called the addNumbers we created without an object. When we run this program, here is the output we will get:

```

Products: 125 # See above

```

There were no surprises there. This approach is controlled as at each place, it is possible to create a static method out of a class method as well. Let’s see another approach with the same example here.


Using @staticmethod

This is a more subtle way of creating a Static method as we do not have to rely on a statement definition of a method being a class method and making it static at each place you make it static.


Let’s use this annotation in a code snippet:

```

class Calculator:

    # create addNumbers static method

    @staticmethod

    def addNumbers(x, y):

        return x + y


>>print('Product:', Calculator.addNumbers(15, 110))

```

When we run this program, here is the output we will get

```

Products: 125 # See above

```

This was actually a much better way to create a static method as the intention of keeping the method static is clear as soon as we create it and mark it with the @staticmethod annotation.


Advantages of Python static method

Static methods have a very clear use-case. When we need some functionality not w.r.t an Object but w.r.t the complete class, we make a method static. This is pretty much advantageous when we need to create Utility methods as they aren’t tied to an object lifecycle usually.

Finally, note that in a static method, we don’t need the self to be passed as the first argument.


- Difference between 'cls' and 'self' in Python classes?

Function and method arguments:

* Always use self for the first argument to instance methods.

* Always use cls for the first argument to class methods.

There is difference between 'self' and 'cls' used method though analogically they are at same place

```

def moon(self, moon_name):

    self.MName = moon_name


#but here cls method its use is different 

@classmethod

def moon(cls, moon_name):

    instance = cls()

    instance.MName = moon_name

```

Now you can see both are moon function but one can be used inside class while other function name moon can be used for any class.

For practical programming approach :

While designing circle class we use area method as cls instead of self because we don't want area to be limited to particular class of circle only .

Example: 

If you want to access a method via instance, keep first parameter as self.

```

class Test:

   def hello(self, name):

      print ('hello ', name)


obj = Test()

obj.hello('Rahul')

```

If you want to access method using class name like we do in static class, better you use cls as first parameter in method

```

class Test:

       def hello(cls, name):

          print ('hello ', name)


Test.hello('Rahul')

```


Property Decorator - @property

The @property decorator is a built-in decorator in Python for the property() function. Use @property decorator on any method in the class to use the method as a property.


You can use the following three decorators to define a property:

@property: Declares the method as a property.

@<property-name>.setter: Specifies the setter method for a property that sets the value to a property.

@<property-name>.deleter: Specifies the delete method as a property that deletes a property.


* Declare a Property

The following declares the method as a property. This method must return the value of the property.

Example: @property decorator

```

class Student:

    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name

```

Above, @property decorator applied to the name() method. The name() method returns the private instance attribute value __name. So, we can now use the name() method as a property to get the value of the __name attribute, as shown below.

Example: Access Property decorator

```

>>> s = Student('Steve')
>>> s.name 
'Steve'

```

* Property Setter

Above, we defined the name() method as a property. We can only access the value of the name property but cannot modify it. To modify the property value, we must define the setter method for the name property using @property-name.setter decorator, as shown below.

Example: Property Setter

```

class Student:

    def __init__(self, name):
        self.__name=name

    @property
    def name(self):
        return self.__name

    @name.setter   #property-name.setter decorator
    def name(self, value):
        self.__name = value

```

Above, we have two overloads of the name() method. One is for the getter and another is the setter method. The setter method must have the value argument that can be used to assign to the underlying private attribute. Now, we can retrieve and modify the property value, as shown below.

Example: Access Property

```

>>> s = Student('Steve')
>>> s.name 
'Steve'
>>> s.name = 'Bill'
'Bill'

```

* Property Deleter

Use the @property-name.deleter decorator to define the method that deletes a property, as shown below.

Example: Property Deleter

```

class Student:
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name
    
    @name.setter
    def name(self, value):
        self.__name=value
    
    @name.deleter   #property-name.deleter decorator
    def name(self, value):
        print('Deleting..')
        del self.__name

```

The deleter would be invoked when you delete the property using keyword del, as shown below. Once you delete a property, you cannot access it again using the same instance.

Example: Delete a Property

```

>>> s = Student('Steve')
>>> del s.name 
Deleting.. 
>>> s.name 
Traceback (most recent call last):                              
File "<pyshell#16>", line 1, in <module>            
    p.name                                                      
File "C:\Python37\test.py", line 6, in name                     
    return self.__name                                          
AttributeError: 'Student' object has no attribute '_Student__name'

```


Ref python-class python-static-method difference-between-cls-and-self-in-python-classes property-decorator


Comments

Popular posts from this blog

Concurrency in Web Development

Big-O notation basics for web developers