Questions addressed in this post:
- How can I define functions in Python and what are parameters?
- What is Advanced Parameter Handling For Functions?
- How can I use args(*) and kwargs(**) in Python?
What you will learn:
- Define a function that takes parameters.
- Args(* Arguments) and kwargs(** Keyword Arguments) and how to use them.
- Set default values for function parameters.
- Explain how we can use args(*) and kwargs(*) for Advanced Parameter Handling For Functions and Decorators
Ok so let’s dive in the code. Also read the code comments for better understanding:
args and kwargs in python – Mystery of Asterisks in Python
A) When Asterisk used in multiplication and power operations
2 * 3
6
2 ** 3
8
# # Initialize the zero-valued list with 100 length
zeros_list = [0] * 10
print(zeros_list)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] B) args and kwargs in python Functions and their arguments in Python 1) Anatomy of a Function
def fahr_to_celsius(temp):
return ((temp - 32) * (5/9))
conv_temp = fahr_to_celsius(273)
print(conv_temp)
133.88888888888889
print('freezing point of water:', fahr_to_celsius(32), 'C')
print('boiling point of water:', fahr_to_celsius(212), 'C')
freezing point of water: 0.0 C boiling point of water: 100.0 C
2) Parameter Handling
def adder(a,b):
sum_amt = a + b
return sum_amt
amt = adder(2,4)
print(amt)
6
amt = adder(2,4,7)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-21-ca38331a5c84> in <module>() ----> 1 amt = adder(2,4,7) TypeError: adder() takes 2 positional arguments but 3 were given
ERROR :
TypeError: adder() takes 2 positional arguments but 3 were given
def adder_revised(a,b,c):
sum_amt = a + b + c
return sum_amt
amt = adder_revised(2,4,7)
print(amt)
13
# The line below will generate error and is for the demonstration purpose
amt = adder_revised(2,4)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-98-5bc59d53d483> in <module>()
1 # The line below will generate error and is for the demonstration purpose
----> 2 amt = adder_revised(2,4)
TypeError: adder_revised() missing 1 required positional argument: 'c'
ERROR:
TypeError: adder_revised() missing 1 required positional argument: ‘c’
3) Concept of Advanced Parameters and Functions
import datetime
now = datetime.datetime.now()
print('Datetime Now is : ', now)
Datetime Now is : 2019-03-30 11:03:08.381734 Functions with Keyword Arguments
# Arguments with Keyword
day1 = datetime.timedelta(days=1)
delta_day = now - day1
print('Datetime Now is : ', now)
print('Delta Day is : ', delta_day)
Datetime Now is : 2019-03-30 11:03:08.381734 Delta Day is : 2019-03-29 11:03:08.381734 Same function different keyword argument
now = datetime.datetime.now()
print('Datetime Now is : ', now)
day1 = datetime.timedelta(hours=4)
delta_day = now - day1
print('Delta Day is : ', delta_day)
Datetime Now is : 2019-03-30 11:06:50.388904 Delta Day is : 2019-03-30 07:06:50.388904
Same function with Multiple Keyword Argument
now = datetime.datetime.now()
print('Datetime Now is : ', now)
day1 = datetime.timedelta(days=1,hours=4)
delta_day = now - day1
print('Delta Day is : ', delta_day)
Datetime Now is : 2019-03-30 11:08:03.531606 Delta Day is : 2019-03-29 07:08:03.531606 Optional Arguments Lets revamp our adder function with keyword Argument
def new_adder(a,b,c=0):
sum_amt = a + b + c
return sum_amt
amt = new_adder(2,4)
print(amt)
6
amt = new_adder(2,4,7)
print(amt)
13
amt = new_adder(2,4,7,10)
print(amt)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-14-665b09d0593c> in <module>()
----> 1 amt = new_adder(2,4,7,10)
2 print(amt)
TypeError: new_adder() takes from 2 to 3 positional arguments but 4 were given
TypeError: new_adder() takes from 2 to 3 positional arguments but 4 were given
4) Unlimited Number of Positional Argument Values
def smart_adder(*args):
amt = 0
for n in args:
amt += n
print("Sum:",amt)
return amt
smart_adder(3,5)
smart_adder(4,5,6,7)
smart_adder(1,2,3,5,6)
smart_adder(2,3,5,6,8,9,7)
Sum: 8 Sum: 22 Sum: 17 Sum: 40
def smart_adder(*num):
amt = 0
for n in num:
amt += n
print("Sum:",amt)
return amt
smart_adder(3,5)
smart_adder(4,5,6,7)
smart_adder(1,2,3,5,6)
smart_adder(2,3,5,6,8,9,7)
Sum: 8 Sum: 22 Sum: 17 Sum: 40 40 In Python, we can pass a variable number of arguments to a function using special symbols. There are two special symbols: *args (Non Keyword Arguments) **kwargs (Keyword Arguments) We use *args and **kwargs as an argument when we are unsure about the number of arguments to pass in the functions. You would use *args when you're not sure how many arguments might be passed to your function, i.e. it allows you pass an arbitrary number of arguments to your function. Keyword Arguments with variable number of keys
def intro(**data):
print("\nData type of argument:",type(data))
for key, value in data.items():
print("{} is {}".format(key,value))
intro(Firstname="Ali", Lastname="Mohammed", Phone=1234567890)
intro(Firstname="Ali", Lastname="Raza", Email="alirazabhayani@gmail.com", Country="Pakistan", Phone=9876543210)
Data type of argument: <class 'dict'> Firstname is Ali Lastname is Mohammed Phone is 1234567890 Data type of argument: <class 'dict'> Firstname is Ali Lastname is Raza Email is alirazabhayani@gmail.com Country is Pakistan Phone is 9876543210
Ordering Arguments When ordering arguments within a function or function call, arguments need to occur in a particular order: Formal positional arguments *args Keyword arguments **kwargs
def func(required_arg, *args, **kwargs):
# required_arg is a positional-only parameter.
print(required_arg)
# args is a tuple of positional arguments,
# because the parameter name has * prepended.
if args: # If args is not empty.
print(args)
# kwargs is a dictionary of keyword arguments,
# because the parameter name has ** prepended.
if kwargs: # If kwargs is not empty.
print(kwargs)
# Expected to generate an error as no arguments passed
func()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-67-ae433acc38da> in <module>()
1 # Expected to generate an error as no arguments passed
----> 2 func()
TypeError: func() missing 1 required positional argument: 'required_arg'
func("This is a required argument")
This is a required argument
func("This is a required argument", 1, 2, '3')
This is a required argument (1, 2, '3')
func("This is a required argument", 1, 2, '3', keyword1=4, keyword2="foo")
This is a required argument
(1, 2, '3')
{'keyword1': 4, 'keyword2': 'foo'}
Whats the point of this all?
Why should we even bother ourselves with the Advanced Function Parameter?
One place where the use of *args and **kwargs is quite useful is for subclassing
class Foo(object):
def __init__(self, value1, value2):
# do something with the values
print(value1, value2)
class MyFoo(Foo):
def __init__(self, *args, **kwargs):
# do something else, don't care about the args
print('myfoo')
super(MyFoo, self).__init__(*args, **kwargs)
This way we can extend the behaviour of the Foo class, without having to know too much about Foo. This can be quite convenient if you are programming to an API which might change. MyFoo just passes all arguments to the Foo class
DECORATORS:
Decorators are very powerful and useful tool in Python since it allows programmers to modify the behavior of function or class. Decorators allow us to wrap another function in order to extend the behavior of wrapped function, without permanently modifying it.
In Decorators, functions are taken as the argument into another function and then called inside the wrapper function.
def pass_thru(func_to_decorate):
def new_func(*original_args, **original_kwargs):
print("Function has been decorated. Congratulations.")
# Do whatever else you want here
new_args = []
for name in original_args:
new_args.append(name.title())
print('Coverting %s to %s ' %(name,name.title()))
return func_to_decorate(*new_args, **original_kwargs)
return new_func
@pass_thru
def print_args(*args):
print('Entered Function now')
for arg in args:
print(arg)
print_args('ALI', 'RaZa', 'BhaYanI')
Function has been decorated. Congratulations. Coverting ALI to Ali Coverting RaZa to Raza Coverting BhaYanI to Bhayani Entered Function now Ali Raza Bhayani
@pass_thru
def print_2args(a,b):
print('Entered Function now')
print('Final Inputs I got : ', a,b)
print_2args('ALI', 'RaZa')
Function has been decorated. Congratulations. Coverting ALI to Ali Coverting RaZa to Raza Entered Function now Final Inputs I got : Ali Raza
@pass_thru
def print_3args(a,b,c):
print('Entred Function now')
print('Final Inputs I got : ',a,b,c)
print_3args('ALI', 'RaZa', 'BhaYanI')
Function has been decorated. Congratulations. Coverting ALI to Ali Coverting RaZa to Raza Coverting BhaYanI to Bhayani Entred Function now Final Inputs I got : Ali Raza Bhayani

