<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
Step1:  Object Oriented Programming
In Object Oriented Programming, everything is an object. Objects are real world entities having some attributes and some related methods that operate on attributes. We assume that the reader has some familiarity with Object Oriented Concepts such as Inheritance, Polymorphism, Abstraction and so on ...
Defining Classes
Syntax
Step2:  Duck Typing and Interfaces
In C, C++, Java and C#, we have to predefine the data type of every variable declared. In Python, you may have observed that you are not defining any data type during variable declaration. In fact, Python does not require you to do that.
In C,
c
    int x;
means storage space allocated to x is constant 8 bytes (on x64 system) and this space will never change. This also implies that x will never hold other values than int. Trying to do so will raise a compiler error. This nature of C makes the language statically typed, i.e., data type of a variable is determined at the compile time.
On the other hand, in Python, the type of variable is determined entirely during runtime. Storage space allocated to a variable can vary dynamically. When we assign a string to a variable x, it will be str. If we reassign it to a list, it will be list. This nature of Python makes it dynamically typed language. It is also called as Duck typing.
Duck typing is an application of the duck test in type safety. It requires that type checking be deferred to runtime, and is implemented by means of dynamic typing or reflection.
The Duck test is a humorous term for a form of abductive reasoning. This is its usual expression
Step3:  type() - Obtaining the data type of a variable
<ASSISTANT_TASK:>
Python Code:
class Student:
    count = 0 # Total number of objects created so far, it is static variable as it is declared outside
    
    def __init__(self,name,usn,marks):
        
        Constructor of class Student
        Input: name - name of the student : string
               usn  - university serial number : string
               marks - marks in 3 subjects out of 20
        
        Student.count += 1
        self.name = name 
        self.usn  = usn
        self.marks = marks[:] # Copy marks to self.marks .. a simple self.marks = marks make only reference equal
    
    def print_details(self):
        print(str(self))
    
    def total_marks(self):
        return sum(self.marks)
        
    def __iter__(self):
        details = {'name':self.name,'usn':self.usn,'marks':self.marks}
        for k,v in details.items():
            yield k,v # A tuple
    
    def __str__(self):
        return "Name : {0} \nUSN = {1}\nMarks in 3 subjects = {2}".format(self.name,self.usn,self.marks)
    
    @staticmethod
    def get_total_count():
        return Student.count
s1 = Student('Ramesh','4jc11cs111',[20,16,18])
s2 = Student('Ravi','4jc15cs112',[15,18,18])
print(s1) # calls __str__()
print(s2)
Student.count
Student.get_total_count()
for k,v in s1:
    print('{} = {}'.format(k,v))
s1.print_details()       # self of Student.print_details(self) is passed as s1
Student.print_details(s1) # Explicitly passing self parameter
Student.get_total_count()
s1.get_total_count()   # This is also possible, @staticmethod attribute prevents passing object to method
Explanation: Object Oriented Programming
In Object Oriented Programming, everything is an object. Objects are real world entities having some attributes and some related methods that operate on attributes. We assume that the reader has some familiarity with Object Oriented Concepts such as Inheritance, Polymorphism, Abstraction and so on ...
Defining Classes
Syntax:
python
    class ClassName:
        &lt;statement 1&gt;
        &lt;statement 2&gt;
        ....
        ....
        &lt;statement n&gt;
Special Methods inside the class
Unlike C++ and Java classes, class methods does not hold the reference of current object (this object). Class methods should take the class object as their first argument. This is not required for static methods. At the point of invocation of object methods, the object is passed to method implicitly. It is a covention to name the first parameter of class method as self. Now let's see some special functions of classes.
__init__(self,elements) : Constructor, called when object is created. All properties of the object have to be declared here.
__del__(self) : Destructor, called when del is applied to an object.
__str__(self) : Returns the string representation of object. Called when str() is called on the object.
__iter__(self) : Returns the iterator of elements of the object. Called when iter() is called on the object. Also this enables us to use the for ele in object like construct.
__len(self)__ : Returns the length of the collection. Called when len() is invoked on the object.
__getitem(self,item)__ : Allows us to use object[item] like accessor to get an item
Static members and methods
Any member declared inside the class, but not in the methods, are shared by all instances of classes. A method annotated with @staticmethod is static method, and doesn't recieve class object as it's first parameter.
A note on private members
A member or method whose name starts with '__' is regarded as a private member or method.
A sample class, Student
Here we implement a simple Student class.
End of explanation
class Duck:
    def quack(self):
        print("Quaaaaaack!")
    def feathers(self):
        print("The duck has white and gray feathers.")
class Person:
    def quack(self):
        print("The person imitates a duck.")
    def feathers(self):
        print("The person takes a feather from the ground and shows it.")
    def name(self):
        print("John Smith")
def in_the_forest(duck):
    duck.quack()
    duck.feathers()
def game():
    donald = Duck()
    john = Person()
    in_the_forest(donald)
    in_the_forest(john)
game()
Explanation: Duck Typing and Interfaces
In C, C++, Java and C#, we have to predefine the data type of every variable declared. In Python, you may have observed that you are not defining any data type during variable declaration. In fact, Python does not require you to do that.
In C,
c
    int x;
means storage space allocated to x is constant 8 bytes (on x64 system) and this space will never change. This also implies that x will never hold other values than int. Trying to do so will raise a compiler error. This nature of C makes the language statically typed, i.e., data type of a variable is determined at the compile time.
On the other hand, in Python, the type of variable is determined entirely during runtime. Storage space allocated to a variable can vary dynamically. When we assign a string to a variable x, it will be str. If we reassign it to a list, it will be list. This nature of Python makes it dynamically typed language. It is also called as Duck typing.
Duck typing is an application of the duck test in type safety. It requires that type checking be deferred to runtime, and is implemented by means of dynamic typing or reflection.
The Duck test is a humorous term for a form of abductive reasoning. This is its usual expression:
If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.
The duck test can be seen in the following example. As far as the function in_the_forest is concerned, the Person object is a duck:
End of explanation
x = 8
type(x)
type(8.5)
type('hello')
type([1,2,1])
type({})
type((1,))
type(s1)
import random
type(random)
Explanation: type() - Obtaining the data type of a variable
End of explanation
<END_TASK>