{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Idiomatic Python - miscellaneous part 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comprehensions" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "original_data = (1, 2, 3, 4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Don't do this." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# list\n", "square_roots_list = []\n", "for val in original_data:\n", " square_root = val ** (1 / 2)\n", " square_roots_list.append(square_root)\n", "print(square_roots_list)\n", "\n", "# set\n", "square_roots_set = set()\n", "for val in original_data:\n", " square_root = val ** (1 / 2)\n", " square_roots_set.add(square_root)\n", "print(square_roots_set)\n", "\n", "# dict\n", "square_roots_dict = {}\n", "for val in original_data:\n", " square_root = val ** (1 / 2)\n", " square_roots_dict[val] = square_root\n", "print(square_roots_dict)\n", "\n", "# dict with a condition\n", "integer_square_roots_dict = {}\n", "for val in original_data:\n", " square_root = val ** (1 / 2)\n", " if square_root.is_integer():\n", " integer_square_roots_dict[val] = square_root\n", "print(integer_square_roots_dict)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: in case you're using 2.X version of Python for some reason, the result of `1/2` is `0` instead of `0.5`. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Use comprehensions!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "square_roots_list = [val ** (1 / 2) for val in original_data]\n", "print(square_roots_list)\n", "\n", "square_roots_set = {val ** (1 / 2) for val in original_data}\n", "print(square_roots_set)\n", "\n", "square_roots_dict = {val: val ** (1 / 2) for val in original_data}\n", "print(square_roots_dict)\n", "\n", "integer_square_roots_dict = {\n", " val: val ** (1 / 2) for val in original_data if (val ** (1 / 2)).is_integer()\n", "}\n", "print(integer_square_roots_dict)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Using `in` for checking presence of an element in a collection" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "name = \"John Doe\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Don't do it like this." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if name == \"John\" or name == \"Doe\" or name == \"John Doe\":\n", " print(\"This seems to be our guy\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Do it like this!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if name in (\"John\", \"Doe\", \"John Doe\"):\n", " print(\"This seems to be our guy\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Chained comparisons" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a, b, c, d = 1, 2, 3, 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Don't do it like this." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if b > a and c > b and d > c:\n", " print(\"from lowest to highest: a, b, c, d\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Do it like this!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if a < b < c < d:\n", " print(\"from lowest to highest: a, b, c, d\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Falsy/truthy values" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# These are falsy\n", "my_list = []\n", "my_dict = {}\n", "my_set = set()\n", "my_tuple = tuple()\n", "zero = 0\n", "false = False\n", "none = None\n", "my_str = \"\"\n", "\n", "# Basically the rest are truthy\n", "# for example:\n", "my_second_list = [\"foo\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Don't do it like this." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if len(my_list) == 0:\n", " print(\"Empty list is so empty\")\n", "\n", "if not len(my_dict):\n", " print(\"Empty dict is also very empty\")\n", "\n", "if not len(my_set) and not len(my_tuple):\n", " print(\"Same goes for sets and tuples\")\n", "\n", "if not bool(zero) and not bool(false) and not bool(none) and len(my_str) == 0:\n", " print(\"These are also falsy\")\n", "\n", "if len(my_second_list) > 0:\n", " print(\"This should be true\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### This is much better!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if not my_list:\n", " print(\"Empty list is so empty\")\n", "\n", "if not my_dict:\n", " print(\"Empty dict is also very empty\")\n", "\n", "if not my_set and not my_tuple:\n", " print(\"Same goes for sets and tuples\")\n", "\n", "if not zero and not false and not none and not my_str:\n", " print(\"These are also falsy\")\n", "\n", "if my_second_list:\n", " print(\"This should be true\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `any` & `all`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "example_collection = [\"a\", True, \"Python is cool\", 123, 0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Don't do it like this." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "any_value_truthy = True\n", "for val in example_collection:\n", " if val:\n", " any_value_truthy = True\n", " break\n", "\n", "all_values_truthy = True\n", "for val in example_collection:\n", " if not val:\n", " all_values_truthy = False\n", " break\n", "\n", "print(f\"any truthy: {any_value_truthy}, all truthy: {all_values_truthy}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Do it like this!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "any_value_truthy = any(example_collection)\n", "all_values_truthy = all(example_collection)\n", "print(f\"any truthy: {any_value_truthy}, all truthy: {all_values_truthy}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Pythonic substitute for ternary operator\n", "Many other programming languages have a ternary operator: `?`. A common use case for the ternary operator is to assign a certain value to a variable based on some condition. In other words, it could be used like this:\n", "```\n", "variable = some_condition ? some_value : some_other_value\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instead of doing this." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "some_condition = True # just a dummy condition\n", "\n", "if some_condition:\n", " variable = \"John\"\n", "else:\n", " variable = \"Doe\"\n", "print(variable)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### You can do it like this!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "variable = \"John\" if some_condition else \"Doe\"\n", "print(variable)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Function keywords arguments\n", "For better readability and maintainability." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def show_person_details(name, is_gangster, is_hacker, age):\n", " print(f\"name: {name}, gangster: {is_gangster}, hacker: {is_hacker}, age: {age}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is not good. It's hard to tell what `True`, `False` and `83` refer here if you are not familiar with the signature of the `show_person_details` function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "show_person_details(\"John Doe\", True, False, 83)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### This is much better!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "show_person_details(\"John Doe\", is_gangster=True, is_hacker=False, age=83)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Extra: keyword only arguments after `*`\n", "This might be useful for example if the signature of the function is likely to change in the future. For example, if there's even a slight chance that one of the arguments may be dropped during the future development, consider using `*`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def func_with_loads_of_args(arg1, *, arg2=None, arg3=None, arg4=None, arg5=\"boom\"):\n", " pass\n", "\n", "\n", "# This won't work because only keyword arguments allowed after *\n", "# func_with_loads_of_args('John Doe', 1, 2)\n", "\n", "# This is ok\n", "func_with_loads_of_args(\"John Doe\", arg4=\"foo\", arg5=\"bar\", arg2=\"foo bar\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Multiple assigment\n", "Let's say we want to swap the values of two variables." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Don't do it like this." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# original values\n", "a = 1\n", "b = 2\n", "\n", "# swap\n", "tmp = a\n", "a = b\n", "b = tmp\n", "print(a, b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Do it like this!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# original values\n", "a = 1\n", "b = 2\n", "\n", "# swap\n", "a, b = b, a\n", "print(a, b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## (Un)packing" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "my_list = [1, 2, 3, 4, 5, 6]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Don't do something like this." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "first = my_list[0]\n", "last = my_list[-1]\n", "middle = my_list[1:-1]\n", "print(first, middle, last)\n", "\n", "packed = [first] + middle + [last]\n", "assert packed == my_list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### This is the Pythonic way!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# unpacking\n", "first, *middle, last = my_list\n", "print(first, middle, last)\n", "\n", "# packing\n", "packed = [first, *middle, last]\n", "assert packed == my_list" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.11.0" } }, "nbformat": 4, "nbformat_minor": 2 }