Python is a hybrid programming language it support both object oriented programming as well as functional programming.
Like everything else in python function are also objects.
In the above example dir() is used to display the objects.
Lets Look at a simple function
basicFunction1.py
At step #1 we are able to access the contents of passed arguments.
step #2 two things happen one, is that we execute the function to be wrapped man()
and the other is that we modify the return value of wrapped function man().
CLASS-DECORATOR
Till Now we have seen decorators which are built using function ,lets try using CLASSES
In the above code foo1() & foo2() are passed as object to class myDecorator.
Now in myDecorator we have defined a __call__() method which gets called each time,
the decorated function gets called.
addOne class adds one to the return value of the decorated function foo()
Like everything else in python function are also objects.
Functions and nested functions
In the above example dir() is used to display the objects.
Lets Look at a simple function
basicFunction1.py
Lets run it
Since function are object they can be assigned to variables.
basicFunction2.py
In basicFunction2.py
At step #1 we assign the variable fun with the function label funIn.
step #2 we call function funIn by adding () -- parentheses to the variable fun.
Now let us consider a function within a function ie.. nested functions.
Moving on to a function which returns a function.
nestedBasics1.py
The the above code has two function funOut()-- outer function & funIn() -- inner function.
At step #1 the funOut() return label of the inner function label
step #2 the variable funCall has the inner function label.
step #3 now the inner function can be called by just adding () -- parentheses to the funCall variable.
Lets us now consider a variation of nestedBasics1.py
nestedBasics2.py[closures]
In the above code
At step #1 we declare variable name.Function funIn() store this value.
step #2 the funOut() return label of the inner function label
step #3 the variable funCall has the inner function label.
step #4 now the inner function can be called by just adding () -- parentheses to the funCall variable.
When the inner function is being called it is able to display the value of name, since funIn() was able to store name value at Runtime (as mentioned in step #1).
Now lets us make nestedBasics2.py more dynamic
Advantage of Nested functions
Lets us examine nestedBasics2.py
At step #1 we are creating a new object of the function funOut()
step #2 we are creating another object of the function funOut()
Now lets us consider the class version of nestedBasics2.py.
funClass.py
In the above code funClass.py,
At step #1 we need define an initializer method __init__()
step #2 we need a regular method to act on the class attribute name.
step #3 we are creating a object of class funOut
step #4 now in order to access regular method we are using .dot operator
If we are writing a class with one regular method, it better to used nested functions.
Function which takes another function
In the above code we have two functions avg() & cal()
cal() --takes a function as one of the input parameters.
*args , **kwargs
A function can have positional arguments which are also know as named and mandatory, the second type of arguments are default which are optional and are also know as keyword arguments.
Positional arguments
In the above code , the function man() take two argument name & age ie positional arguments..
At step #1 we interchange two argument but get the same results(named argument)
step #2 we pass one argument and we get an error message(mandatory argument)
Default(Keyword) arguments
In the above code the function we have has two default arguments
At step #3 when we don't pass any argument the function consider the default values
Output
*args--takes an unlimited number of positional arguments.It prevent the program from crashing,and is used when we don't know the number of input arguments.
*kwargs-- takes an unlimited number of keyword arguments, and store the data in a dictionary.
*args and *kwargs
Decorators
Function without arguments.
Till now we have seen that function are object and few example on nested functions.
Lets us now move on to decorators.
decoratorsbasic1.py
In the above example decoratorsbasic1.py we have two function at runtime ie wrapper() & name()
wrapper() does three things.
1) It take a function as parameter(myFunc)
2)wrapper has an inner function which calls the passed function(myFunc), and store it in variable(y).
3)Finally wrapper return the inner function label(innerFunc)
At step #1 in decoratorsbasic1.py
The innerFunc label is assigned to name and this in turn when executed
changes the return value of the function name().
A slight modification to decoratorsbasic1.py would be done by adding decorator symbol(@)
with the wrapper function label just above the name function.
Lets us consider another example
Function with arguments
In the above code we have are applying a decorators which checks ,that both the input parameter are non-zero and +ve.
Now lets us consider a decorator which can handle any number of positional & keyword arguments.
Let us write a decorators which can only read data passed to the function,but not executed the decorated function itself.
There are two function at runtime ie wrapper() , man().
wrapper does two things
At step #1 the inner function is designed to handle any function signature.
step #2 innerWrap is able to access the argument of the decorated function man()
but it does not executed the contents of man() function.
Now lets access the parameter passed to the function as well execute the function itself.
At step #1 we are able to access the contents of passed arguments.
step #2 two things happen one, is that we execute the function to be wrapped man()
and the other is that we modify the return value of wrapped function man().
CLASS-DECORATOR
Till Now we have seen decorators which are built using function ,lets try using CLASSES
In the above code foo1() & foo2() are passed as object to class myDecorator.
Now in myDecorator we have defined a __call__() method which gets called each time,
the decorated function gets called.
addOne class adds one to the return value of the decorated function foo()