{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<small><small><i>\n",
    "All the IPython Notebooks in **Python Advanced Topics** lecture series by Dr. Milaan Parmar are available @ **[GitHub](https://github.com/milaan9/07_Python_Advanced_Topics)**\n",
    "</i></small></small>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Python __`*args`__ and __`**kwargs`__\n",
    "\n",
    "In this class, we will learn about Python __`*args`__ and __`**kwargs`__ ,their uses and functions with examples."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In programming, we define a function to make a reusable code that performs similar operation. To perform that operation, we call a function with the specific value, this value is called a function argument in Python.\n",
    "\n",
    "We would recommend you to read **[Python Function](https://github.com/milaan9/04_Python_Functions/blob/main/001_Python_Functions.ipynb)** and **[Python Function Arguments](https://github.com/milaan9/04_Python_Functions/blob/main/004_Python_Function_Arguments.ipynb)**.\n",
    "\n",
    "Suppose, we define a function for addition of 3 numbers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-07-31T13:08:44.472274Z",
     "start_time": "2021-07-31T13:08:44.459576Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sum: 46\n"
     ]
    }
   ],
   "source": [
    "# Example 1: Function to add 3 numbers\n",
    "\n",
    "def adder(x,y,z):\n",
    "    print(\"sum:\",x+y+z)\n",
    "\n",
    "adder(12,15,19)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Explanation:**\n",
    "\n",
    "In above program we have **`adder()`** function with three arguments **`x`**, **`y`** and **`z`**. When we pass three values while calling **`adder()`** function, we get sum of the 3 numbers as the output."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lets see what happens when we pass more than 3 arguments in the **`adder()`**  function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-07-31T13:08:44.903013Z",
     "start_time": "2021-07-31T13:08:44.475203Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "adder() takes 3 positional arguments but 5 were given",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-2-986e6d871071>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      2\u001b[0m     \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"sum:\"\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m+\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m+\u001b[0m\u001b[0mz\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[0madder\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m5\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m15\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m20\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m25\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m: adder() takes 3 positional arguments but 5 were given"
     ]
    }
   ],
   "source": [
    "def adder(x,y,z):\n",
    "    print(\"sum:\",x+y+z)\n",
    "\n",
    "adder(5,10,15,20,25)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Explanation:**\n",
    "\n",
    "In the above program, we passed 5 arguments to the **`adder()`** function instead of 3 arguments due to which we got **`TypeError`**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction to __`*args`__ and __`**kwargs`__ in Python\n",
    "\n",
    "In Python, we can pass a variable number of arguments to a function using special symbols. There are two special symbols:\n",
    "\n",
    "* __`*args`__ (Non Keyword Arguments)\n",
    "* __`**kwargs`__ (Keyword Arguments)\n",
    "\n",
    "We use __`*args`__ and __`**kwargs`__ as an argument when we are unsure about the number of arguments to pass in the functions."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Python __*args__\n",
    "\n",
    "As in the above example we are not sure about the number of arguments that can be passed to a function. Python has __`*args`__ which allow us to pass the variable number of non keyword arguments to function.\n",
    "\n",
    "In the function, we should use an asterisk **`*`** before the parameter name to pass variable length arguments.The arguments are passed as a tuple and these passed arguments make tuple inside the function with same name as the parameter excluding asterisk **`*`**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-07-31T13:08:51.348994Z",
     "start_time": "2021-07-31T13:08:51.327507Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sum: 9\n",
      "Sum: 21\n",
      "Sum: 21\n"
     ]
    }
   ],
   "source": [
    "# Example 2: Using *args to pass the variable length arguments to the function\n",
    "\n",
    "def adder(*num):\n",
    "    sum = 0\n",
    "    \n",
    "    for n in num:\n",
    "        sum = sum + n\n",
    "\n",
    "    print(\"Sum:\",sum)\n",
    "\n",
    "adder(3,6)\n",
    "adder(3,5,6,7)\n",
    "adder(1,2,3,6,9)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Explanation:**\n",
    "\n",
    "In the above program, we used __`*num`__ as a parameter which allows us to pass variable length argument list to the **`adder()`** function. Inside the function, we have a loop which adds the passed argument and prints the result. We passed 3 different tuples with variable length as an argument to the function."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Python __`**kwargs`__\n",
    "\n",
    "Python passes variable length non keyword argument to function using __`*args`__ but we cannot use this to pass keyword argument. For this problem Python has got a solution called __`**kwargs`__, it allows us to pass the variable length of keyword arguments to the function.\n",
    "\n",
    "In the function, we use the double asterisk __`**`__ before the parameter name to denote this type of argument. The arguments are passed as a dictionary and these arguments make a dictionary inside function with name same as the parameter excluding double asterisk __`**`__."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-07-31T13:08:57.897046Z",
     "start_time": "2021-07-31T13:08:57.871652Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Data type of argument: <class 'dict'>\n",
      "Firstname is Amy\n",
      "Lastname is Barn\n",
      "Age is 24\n",
      "Phone is 1234567890\n",
      "\n",
      "Data type of argument: <class 'dict'>\n",
      "Firstname is Arthur\n",
      "Lastname is Hunt\n",
      "Email is arthurhunt@yesmail.com\n",
      "Country is Atlantis\n",
      "Age is 27\n",
      "Phone is 9976563219\n"
     ]
    }
   ],
   "source": [
    "# Example 3: Using **kwargs to pass the variable keyword arguments to the function \n",
    "\n",
    "def intro(**data):\n",
    "    print(\"\\nData type of argument:\",type(data))\n",
    "\n",
    "    for key, value in data.items():\n",
    "        print(\"{} is {}\".format(key,value))\n",
    "\n",
    "intro(Firstname=\"Amy\", Lastname=\"Barn\", Age=24, Phone=1234567890)\n",
    "intro(Firstname=\"Arthur\", Lastname=\"Hunt\", Email=\"arthurhunt@yesmail.com\", Country=\"Atlantis\", Age=27, Phone=9976563219)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Explanation:**\n",
    "\n",
    "In the above program, we have a function **`intro()`** with __`**data`__ as a parameter. We passed two dictionaries with variable argument length to the **`intro()`** function. We have for loop inside **`intro()`** function which works on the data of passed dictionary and prints the value of the dictionary.."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Things to Remember:\n",
    "\n",
    "* __`*args`__ and __`**kwargs`__ are special keyword which allows function to take variable length argument.\n",
    "* __`*args`__ passes variable number of non-keyworded arguments list and on which operation of the list can be performed.\n",
    "* __`**kwargs`__ passes variable number of keyword arguments dictionary to function on which operation of a dictionary can be performed.\n",
    "* __`*args`__ and __`**kwargs`__ make the function flexible."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "hide_input": false,
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}