Skip to content

Instantly share code, notes, and snippets.

@ljbelenky
Created August 6, 2020 14:09
Show Gist options
  • Save ljbelenky/2feec53d67479750143a0fed7f4ff99c to your computer and use it in GitHub Desktop.
Save ljbelenky/2feec53d67479750143a0fed7f4ff99c to your computer and use it in GitHub Desktop.
*Args and **KWArgs
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# *args and **kwargs\n",
"\n",
"\n",
"## When we define a function, he have several options for how to identify the arguments.\n",
"\n",
"### The simplest method is by position:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"def some_func(a, b, c):\n",
" return 3*a + 2*b + c\n",
"\n",
"some_func(1,2,3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Another method is by name. This allows us a bit for flexibiity so that we don't need to worry about the order of the arguments when we pass them:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"some_func(c=3, b=2, a=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The arguments to the function can be thought of as a list (where values are defined by position), or a dictionary, (where values are defined by keys).\n",
"\n",
"### So the parameters `a=1,b=2,c=3` can be written either as "
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"args = [1,2,3]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### or"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"kwargs = {'a':1,'b':2,'c':3}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Then, when we call the function, we need to tell it that we are passing arguments as a list that need to be *unpacked* into separate arguments. The `*` indicates list unpacking."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"some_func(*args)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The `**` indicates *keyword* or *dictionary unpacking*"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"some_func(**kwargs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Question: How is this helpful?\n",
"\n",
"## Answer: It makes code more flexible because we can treat the input arguments to our functions as variables."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Example:\n",
"\n",
"### We are used to treating input *values* as variables so we can loop over them:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"for a in range(4):\n",
" print(some_func(a, b = 2, c= 3))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### In this example, we have to know that our function is always going to take the arguments `a`, `b` and `c`. We can pass in variable *values*, but we can't change the names of the arguments that the function is expecting."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### What if we have two functions that not only take different parameters, but different numbers and names of parameters?"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"def func_1(a, b, c):\n",
" return a + b + c\n",
"\n",
"def func_2(w, x, y, z):\n",
" return w + x + y + z"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### It's difficult to make a loop so that we can process both of these functions efficiently. Because `func_1` is expecting three arguments named `a`, `b` and `c` and `func_2` is expecting four arguments `w` - `z`. \n",
"\n",
"### We can't pass `a`, `b` and `c` to `func_2`, nor `w`-`z` to func_1."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### We might have to do something like this:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"6\n",
"22\n"
]
}
],
"source": [
"a = 1\n",
"b = 2\n",
"c = 3\n",
"w = 4\n",
"x = 5\n",
"y = 6\n",
"z = 7\n",
"\n",
"for func in [func_1, func_2]:\n",
" if func is func_1:\n",
" print(func(a,b,c))\n",
" else:\n",
" print(func(w,x,y,z))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### But you can see that these `if` statements are going to get out of hand very quickly. So this is not good."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Instead, we can bundle the arguments into a single variable which contains all the values needed. We can pass the variables to the arguments as package:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"6\n",
"22\n"
]
}
],
"source": [
"functions_and_arguments = [(func_1, [1,2,3]),\n",
" (func_2, [4,5,6,7])]\n",
" \n",
"for func, args in functions_and_arguments:\n",
" print(func(*args))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### This is much simpler because we don't need any `if` statements to handle functions with different signatures."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### For greater flexibility, we can name the arguments:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"6\n",
"22\n"
]
}
],
"source": [
"functions_and_kwarguments = [(func_1, {'a':1,'b':2,'c':3}),\n",
" (func_2, {'w':4,'x':5,'y':6,'z':7})]\n",
"\n",
"for func, kwargs in functions_and_kwarguments:\n",
" print(func(**kwargs))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The great advantage is when we have many similar objects that take different input arguments, but we want to treat them all the same. For example, ML models such as KNN, SVC, LogisiticRegression, etc.\n",
"\n",
"### We can now loop over these models and ensure that each model gets only the parameters it needs, not the parameters of other models.\n",
"\n",
"```\n",
"for model, kwargs in list_of_models_and_arguments:\n",
" model = model(**kwargs)\n",
" model.fit(X_train,y_train)\n",
" model.score(X_train, y_train)\n",
" model.score(X_test, y_test)\n",
" model.predict(X_holdout)\n",
" \n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment