In this post we will see how we could work in python to write some functions which is organised block of reusable code for some special purpose, this provide more reuse ability in python code which also provide flexible , readable, manageable and modulated code.

Python has many builtin functions, same way we could make our own. Let’s do some practice and other stuff on same that could make some concepts clear on same topic which help to write code further.

Defining and calling Python Functions

For defining function in python we have to work on some simple rules which are easy to follow and remember as compared to any other language.

  • Function code block start with def keyword
  • Followed by function name it could anything, better used to name significant to its work. No case requirements, as per PEP (Python Enhancement Proposal) it good to use lower case letter in function name in case two or more words use underscore in between which make it more readability.
  • Followed by parenthesis () which is used to pass argument , followed by colon :
  • Followed by code statements which act as real body of code which write to work on, please follow proper indentation while writing code body.
  • Return statement is optional we could pass final answer through return to any other variable.

After do this theory, let’s do some practical with some small code to see real use of it.

>>> def adder(a,b):
...     print a+b
... 
>>> adder(4,6)
10

So in above code we first create on function called adder and create in such way that it will sum two number and print it.

Please try to match above rules with code, i hope that make you clear about syntax for writing function in python and calling a functions as well

While calling this function we should be sure for passing number of arguments because it should same as we did while defining it.we need to care for this, later we would also see how we could overcome this problem through argument passing method.

With this defining and calling function we have some we also define arguments called formal arguments and when calling it with arguments called actual arguments.

But what if now we pass three argument instead of two or what if pass some string instead of numbers.

>>> adder(4,6,5)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: adder() takes exactly 2 arguments (3 given)

>>> adder(4,str)
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in adder
TypeError: unsupported operand type(s) for +: 'int' and 'type'

So we need bit careful while creating and writing function, it should proper pathway to check every possible break which could cause complete breakdown of your program, that’s where error handling comes in picture which we cover in later posts

Now let’s work on some important part of function that our argument, that we need to pass to function on which compute for us.

Mainly we have four types of argument in python.

  • 1. Position argument
  • 2. Keyword argument
  • 3. Default argument
  • 4. Variable length argument

Let’s discuss through them one by one with some description and examples to understand them more in functional cases.

Position argument

These type of argument are of basic one that we used till now, in this we provided argument while calling function are in same position as they defined while creating argument. To make it more clear let me create one suitable function.

>>> def country(country,capital):
...     print(country+"\'s capital is", capital)
... 
>>> country("India","Delhi")
India's capital is Delhi

We created function in such a way that while calling it we should provide first argument as its country name and second is capital name, What if while calling someone provide it in wrong order, functions will not work as requested.So here now we know position of argument of very important.

>>> country("Delhi","India")
Delhi's capital is India

So now as above someone called function but provide argument in wrong order that create complete mess. This could worse if function has more operation that depend on arguments data type, like below.

>>> def right_to_vote(name,age):
...     if age >= 18:
...             print(name, "can vote")
...     else:
...             print(name, "can\'t vote")
... 
>>> right_to_vote("Ayaan",9)
Ayaan can't vote

In this function we are doing some more complex operation with age that should have some int data type, so what if miss particular order.

>>> right_to_vote(9,"Ayaan")
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in right_to_vote
TypeError: '>=' not supported between instances of 'str' and 'int'

So now i think its clear to everyone that how it work and what exact mess could happen if we work like this without knowing proper order of argument.

Let’s work on another type of argument which could work to make this workaround for this situation.

Keyword Argument

This type of argument could work even in those situation where we don’t know in which order we have arrange formal argument in functions. Let’s see how its work in below code.

>>> def country(country,capital):
...     print(country+"\'s capital is", capital)
...
>>> country(capital="Delhi",country="India")
India's capital is Delhi
>>>

Like in above code we already mentioned argument name (keywords) with their values because of that we could see there is nothing happen wrong with this function. As we mentioned keywords it called as keyword arguments.

Default Argument

But what if only provide one argument instead of two where it ask for two argument, in that case it will through an error like below

>>> country(capital="Delhi")
Traceback (most recent call last):
  File "", line 1, in 
TypeError: country() missing 1 required positional argument: 'country'

In those cases we could use default argument like below.

>>> def car(made,model,top_speed=100):
...     print("This car",made, model, "top speed of", top_speed)
... 
>>> car("Maruti","swift") No top_speed
This car Maruti swift top speed of 100

>>> car("Maruti","swift",180) top speed defined
This car Maruti swift top speed of 180

So with above code you get to know if we provide argument while calling function, it will work with same but if not it will pick default value provided in function definition itself.

This is really good way to define some default value in function definition itself which make it feasible to provide detail in case argument is not passed while calling it.

Variable length Argument

But what if someone put some extra argument, like below code

>>> def car(made,model,top_speed):
...     print("This car",made, model, "top speed of", top_speed)
... 
>>> car("Maruti","swift",180,1200)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: car() takes 3 positional arguments but 4 were given
>>> 

For such condition we could do some other things like below.

>>> def car(made,model,*top_speed):
...     print("This car",made, model, "top speed of", top_speed[0])
...     print(type(top_speed))
...
>>> car("Maruti","swift",180,1200)
This car Maruti swift top speed of 180
<class 'tuple'>

So As mentioned above code, if we use * asterisk in last argument, calling it will create tuple with all data type and we could extract first element of it and ignore other. But with this approach i don’t think we have great use of in case we need to use these extra argument as we don’t how to use these arguments, but still we could have some use case like below.

>>> def add(*a):
...     sum=0
...     for i in a:
...             sum=sum+i
...     print(sum)
... 
>>> add(7,4,8)
19
>>> add(1)
1
>>> add(756,97,563)
1416

So in above whatever argument number we could sum them up and print it on screen, this way we used every provided argument in code. But still has no keyword all arguments used for same purpose. In below statements, we tried to find what could we do make it more usable for some code which has defined keyword to use arguments in different possible ways.

So is there any solution in which we could also have some keys bind to these extra arguments , yes Variable length keyword argument which would work like below.

>>> def car(made,model,**top_speed):
...     print("This car",made, model)
...     print(top_speed)
...     print(type(top_speed))
...
>>> car("Maruti","swift",top_speed=180,Capacity=1197)
This car Maruti swift
{'top_speed': 180, 'Capacity': 1197}
<class 'dict'>

So in above code we added two * asterisk before last argument which make dictionary and because we already assign keywords on them, we have nice formatted dictionary with key/values. Which could be use in nice way in code with proper arrangement as compared of tuples where we don’t have any keywords where it need to assign.

Just to use it here itself with some small code, we could write it like below in for loop.

>>> def car(made,model,**top_speed):
...     print("This car",made, model)
...     for key,value in top_speed.items():
...             print(key,"---",value)
... 
>>> car("Maruti","swift",top_speed=180,Capacity=1197)
This car Maruti swift
top_speed --- 180
Capacity --- 1197