PREV
Here we are going to discuss about advance topics in python.They are
1. Python Iterator
2. Python Generator
3. Python @Property
4. Python Decorator
1. Python Iterators:
Iteration is a simple an object,it can be iterated upto given limit.It can allow the user to access or traverse through the all items which are collected without any prior knowldge
Python Iterator has been implemented by using iterator tool,it is consists of two Methods.They are
1. __iter__()
2. __next__()
1. __iter__():
This method returns an iterator object
2. __next__():
- This method returns the next element in the sequence of an object
- Before going to discuss about this methods ,we will little understanding the standard loops.
Take an example as a for loop
here we can consider list which have the elements as an int
1 2 3 4 5 |
data=[1,2,3,4,5] for i in data: print (“i is:”,i) |
Output:
1 2 3 4 5 6 7 8 9 |
1 2 3 4 5 |
Now we can go thorough internally,what is happening
- When we are going to work with loops internally it will use __iter__() and __next__() methods,here __iter__() will iterate the items one by one and __next__() will print the next items in collected.
Now below we are going to demonstrate the usage of iter and next.
>>> data=[1,2,3,4,5]
>>> d_obj=iter(data)
>>> next(d_obj)
1
>>> next(d_obj)
2
>>> next(d_obj)
3
>>> next(d_obj)
4
>>> next(d_obj)
5
>>> next(d_obj)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
StopIteration
>>>
Below is the schematic representation of above example
Implement user defined iterator
Here we are going to create our own user defined iterartor with the help of __next__() and __iter__() methods.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
class OwnIterator: """User defined implementation for Own Iterator""" def __init__(self, num = 0): self.number = num def __iter__(self): self.x = 1 return self def __next__(self): if self.x <= self.number: own_iterator= self.x self.x += 1 return own_iterator else: raise StopIteration for x in OwnIterator(10): print("Num is:",x) |
Output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Num is: 1 Num is: 2 Num is: 3 Num is: 4 Num is: 5 Num is: 6 Num is: 7 Num is: 8 Num is: 9 Num is: 10 |
Implement user defined infinite iterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
class OwnIterator: """Class to implement iterator protocol""" def __init__(self, num = 0): self.num = num def __iter__(self): self.x = 1 return self def __next__(self): own_iterator = self.x self.x += 1 return own_iterator for x in OwnIterator(): if x < 5: print ("Num is:",x) else: break |
Output:
1 2 3 4 5 6 7 |
Num is: 1 Num is: 2 Num is: 3 Num is: 4 |
2. Python Generator
Before we are going to discuss about the Generator ,here we need to discuss about the “yield” keyword
Yield Keyword:
- yield is keyword,it is used return the value from the function to the caller,but while returning the value it will pause the function and then return ,once caller received the value again it will resume the execution where it has been started.
- By using this keyword we can return more than one value.If the programmer using the yield keyword in function then we can call it as a generator .Generator is not normal functions and it will not destroy the local variables.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
def print_odd(data) : for x in data: if x % 2 == 1: yield x data = [1, 4, 5, 6, 7] print ("The odd numbers in list are : ", end = " ") for i in print_odd(data): print (i, end = " ") print("\n") |
Output:
1 |
The odd numbers in list are : 1 5 7 |
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
def SquareOfNums(): x = 1; while True: yield x*x x += 1 for num in SquareOfNums(): if num > 32: break print("num is:",num) |
Output:
1 2 3 4 5 6 7 8 9 |
num is: 1 num is: 4 num is: 9 num is: 16 num is: 25 |
Advantages:
1.It can strore the local variable state,so overhead of memory allocation has been controlled
2.It will retain the old state ,so flow will not start from the begining
Disadvantages:
1. Understanding of the souce code is little difficult.
Now we can enter into the Generators.
Generators:
- Generators are also like normal functions,But the difference is generatiors will have yield keyword,functions will have return statement.
- Syntatically also Generators and functions are different
Function Synatx:
def fun_name():
statements
return data
Generator Synatx:
def gen_name():
statements
yield data
Python Generator with Iterator:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
def menu_card(): yield("Idly") yield("Dosa") yield("Poori") yield("Vada") object=menu_card() print("Next item is:",next(object)) print("Next item is:",next(object)) print("Next item is:",next(object)) print("Next item is:",next(object)) print("Next item is:",next(object)) |
Output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Next item is: Idly Next item is: Dosa Next item is: Poori Next item is: Vada Traceback (most recent call last): File "dummy4.py", line 11, in <module> print("Next item is:",next(object)) StopIteration |
Python Generator working with loops
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def menu_card(): yield("Idly") yield("Dosa") yield("Poori") yield("Vada") for item in menu_card(): print("Next item is:",item) |
Output:
1 2 3 4 5 6 7 |
Next item is: Idly Next item is: Dosa Next item is: Poori Next item is: Vada |
Python recursive Generator working with loops
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
def evennum(x): if x%2==0: yield x yield from evennum(x+1) for num in evennum(2): if num<10: print ("Num is:",num) else: break |
Output:
1 2 3 4 5 6 7 |
Num is: 2 Num is: 4 Num is: 6 Num is: 8 |
Python Generator Expression:
1 2 3 4 5 |
cubeOfNum = (x ** 3 for x in range(10)) for x in cubeOfNum: print("Cube of Num is:",x) |
Output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Cube of Num is: 0 Cube of Num is: 1 Cube of Num is: 8 Cube of Num is: 27 Cube of Num is: 64 Cube of Num is: 125 Cube of Num is: 216 Cube of Num is: 343 Cube of Num is: 512 Cube of Num is: 729 |
3. Python @Property:
In this tutorial we are going to discuss about setter, getter and delete with respect to @property,what use of @property over normal methods,what the solution we can get by using @property.Before going to discuss about the topic we can go through the some basic concepts.
What is attributes in python?
- Attributes are nothong an item that can takes the value associated with class and object.
- If the attribute is respect to class we can tell as class attributes .If the attribute is respect to instace we can tell as instance attributes.
- Here class attributes are shared by every object,but instance attributes are shared individual objects
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
class attr: c_attr=1 def __init__(self,value): self.value=value def dispaly(self): print("Class Attribute:",self.c_attr) print("Instance Attribute:",self.value) obj1=attr(10) obj2=attr(20) print("Object1 Details") obj1.dispaly() print("Object2 Details") obj2.dispaly() |
Output:
1 2 3 4 5 6 7 8 9 10 11 |
Object1 Details Class Attribute: 1 Instance Attribute: 10 Object2 Details Class Attribute: 1 Instance Attribute: 20 |
1. If we observe the above example we have created two attributes they are c_attr is a class attribute ,value is the instance attribute
2. c_attr is assigned with some data i.e 1
3. value is initialized in __init__ function
4. I have created one display method to print the data
5. I have created two objects,obj1 created the for the value of “10”,obj2 created the for the value of “20”
6. If we observe while we are going to access the data for individual objects i am gettig the specific value for instance attribute objects,getting same value for both objects in case of class attributes
Why do we want @property?
Let’s we can go through below example
Example:
class Employee:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
def __init__(self,first,last): self.first = first self.last = last self.email=first+ '.' +last+ '@gmail.com' def fullname(self): return '{} {}'.format(self.first,self.last) emp=Employee('ram','rahim') print(emp.first) print(emp.email) print(emp.fullname()) |
Output:
1 2 3 4 5 |
ram ram.rahim@gmail.com ram rahim |
As we seen above example ,we have created employee class,three attributes first,last and email and __init__method,fullname method we have created.Then we have created ’emp’ object for Employee class then we have printed the attributes of class and fullname method,upto here no problem we got the expected output
Now if we add below line of the code into source code after immediate create the object,then see
emp.first=’raju’
after add this line if we excute the script will get the output like below
raju
ram.rahim@gmail.com
raju rahim
if we saw above output we got expected output for first name and full name ,but we got email is still old one,so to overcum this we need @property
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Employee: def __init__(self,first,last): self.first = first self.last = last self.email=first+ '.' +last+ '@gmail.com' def fullname(self): return '{} {}'.format(self.first,self.last) emp=Employee('ram','rahim') emp.first='raju' print(emp.first) print(emp.email) print(emp.fullname()) |
Output:
1 2 3 4 5 |
raju ram.rahim@gmail.com raju rahim |
How to resolve above issue without using @property with help of setter and getter methods
Example:
class Employee:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
def __init__(self,first,last): self.first = first self.last = last def email(self): return '{}.{}@gmail.com'.format(self.first,self.last) def fullname(self): return '{} {}'.format(self.first,self.last) emp=Employee('ram','rahim') emp.first='raju' print(emp.first) print(emp.email()) print(emp.fullname()) |
Output:
1 2 3 4 5 |
raju raju.rahim@gmail.com raju rahim |
Now we done few minor changes for above code,here we changed the email attribute as the email method ,so now we are getting the expected output,but here the problem might people are using this class.But for this change if any users are using this class, user will be in problematic state and if the code size less no issue,if it have huge lines of code then it is difficult to change this many lines of code.so to overcum this problem we are going to use the @property
How to use the @property