{"id":30684305,"url":"https://github.com/chimpler/python-functional-guide","last_synced_at":"2025-09-01T20:16:00.109Z","repository":{"id":31833663,"uuid":"35400596","full_name":"chimpler/python-functional-guide","owner":"chimpler","description":"Small guide for those transitioning from a functional programming language to Python","archived":false,"fork":false,"pushed_at":"2019-03-04T20:44:34.000Z","size":15,"stargazers_count":21,"open_issues_count":0,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-03-26T23:58:55.975Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chimpler.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-11T03:43:43.000Z","updated_at":"2024-03-26T23:58:55.975Z","dependencies_parsed_at":"2022-09-25T04:22:15.572Z","dependency_job_id":null,"html_url":"https://github.com/chimpler/python-functional-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/chimpler/python-functional-guide","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chimpler%2Fpython-functional-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chimpler%2Fpython-functional-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chimpler%2Fpython-functional-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chimpler%2Fpython-functional-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chimpler","download_url":"https://codeload.github.com/chimpler/python-functional-guide/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chimpler%2Fpython-functional-guide/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273183240,"owners_count":25059814,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-01T02:00:09.058Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-01T20:15:48.328Z","updated_at":"2025-09-01T20:16:00.099Z","avatar_url":"https://github.com/chimpler.png","language":null,"readme":"Small guide for those transitioning from a functional programming language to Python. We use Scala methods and provide their equivalent in Python.\n\n# Table of Contents\n\n  1. [Iterator, generator, iterable and list](#iterator-generator-iterable-and-list)\n  1. [map](#map)\n  1. [filter and filterNot](#filter-and-filternot)\n  1. [find](#find)\n  1. [contains](#contains)\n  1. [exists](#exists)\n  1. [forall](#flatten)\n  1. [flatMap](#flatmap)\n  1. [reduce](#reduce)\n  1. [zipWithIndex](#zipwithindex)\n  1. [take](#take)\n  1. [takeWhile](#takewhile)\n  1. [dropWhile](#dropwhile)\n  1. [scanLeft](#scanleft)\n  1. [zip](#zip)\n  1. [groupby](#groupby)\n  1. [reverse](#reverse)\n  1. [head and headOption](#head-and-headoption)\n  1. [last and lastOption](#head-and-lastoption)\n  1. [getOrElse](#getorelse)\n  1. [min and max](#min-and-minby)\n  1. [minBy and maxBy](#max-and-maxby)\n  1. [sort and sortBy](#sort-and-sortBy)\n  1. [sum](#sum)\n  1. [union](#union)\n  1. [slide](#slide)\n  1. [set-operations](#set-operations)\n  1. [dictionary-operations](#dictionary-operations)\n  1. [case class](#case-class)\n\n### Iterator, generator, iterable and list\nAn iterator is a stateful helper object that will return the next value when calling the method `next()`. A generator is a special kind of iterator that\none can write using the `yield` keyword or using a generator comprehension.\n\nFor instance the function `next_pow2` returns the next power of 2:\n```python\ndef next_pow2():\n   pow = 1\n   while True:\n       yield pow\n       pow *= 2\n\n\u003e it = next_pow2()\n\u003e it\n\u003cgenerator object next_pow2 at 0x101e19b90\u003e\n\u003e it.next()\n1\n\u003e it.next()\n2\n```\n\nYou can also create a generator using a generator comprehension:\n```python\n\u003e import sys\n\u003e it = (2 ** i for i in xrange(sys.maxint))\n\u003e it\n\u003cgenerator object \u003cgenexpr\u003e at 0x101f25280\u003e\n\u003e it.next()\n1\n\u003e it.next()\n2\n```\n\nThe generator creates the next value lazily whenever the `next` method is called.\n\nAn iterable is an object that has a reference to an iterator (through the method `__iter__`). In Python, an iterator is itself an iterable and has the method `__iter__` returning\nitself.  A list (e.g., `[1, 2, 3]`) and a tuple (e.g., `(1, 2, 3)`) are also iterables. You can convert an iterable to iterator using the `iter` function:\n```python\n\u003e l = [1, 2, 3]\n\u003e iter(l) # same as t.__iter__()\n\u003clistiterator at 0x1082afe10\u003e\n\u003e t = (1, 2, 3)\n\u003e iter(t)\n\u003ctupleiterator at 0x1082afb10\u003e\n```\n\nList and tuples are called sequence since we can access any of their element directly using their index (e.g., `l[0]`).\n\nUsing a list or iterator depends on the use case. If the data is going to be read once, it would make sense to use an iterator. If the data is small\nit's usually not important whether you use an iterator or a list.\nUsing a tuple instead of a list makes sense when there is a structure (e.g., the first element is X and the second element is Y) and the number of elements doesn't change from\na tuple to the other.\n\nIn the following, we'll favor generator over list as they are more memory efficient and can easily be converted to a list (e.g., `list(it)`)\n\n### map\nThe `map` function applies a function to each element of an iterable\n\nYou can use the `imap()` function:\n```python\ndef double(x):\n    return x * 2\n\n\u003e from itertools import imap\n\u003e res = imap(double, [1, 2])\n\u003e list(res)\n[2, 4]\n\n\u003e res = imap(lambda x: x * 2, [1, 2])\n\u003e list(res)\n[2, 4]\n```\nNote: There is also a `map` function but it returns a list and not a generator:\n\nOr more readable using a list comprehension:\n```python\n# create a list\n\u003e [x * 2 for x in [1, 2]]\n[2, 4]\n\n# create a generator\n\u003e (x * 2 for x in [1, 2])\n\u003cgenerator object \u003cgenexpr\u003e at 0x10379ee10\u003e\n```\n\n### filter and filterNot\nThe `filter` function keeps elements of an iterable that matches a condition. `filterNot` keeps elements of the iterable that does not match a condition\n\nYou can use the `ifilter()` and `ifilterfalse` functions:\n```python\ndef is_even(x):\n    return x % 2 == 0\n    \nfrom itertools import ifilter\nfrom itertools import ifilterfalse\n\u003e res = ifilter(is_even, [1, 2])\n# res is a generator so we print the result using list(res)\n\u003e list(res)\n[1]\n\n\u003e res = ifilter(lambda x: x % 2 == 0, [1, 2])\n\u003e list(res)\n[1]\n\n\u003e res = ifilterfalse(lambda x: x % 2 == 0, [1, 2])\n\u003e list(res)\n[2]\n```\n\nNote: there is a `filter()` method but it returns a `list` and not a generator.\n\nOr more readable using a list comprehension:\n```python\n# create a list\n\u003e [x for x in [1, 2] if x % 2 == 0]\n[2, 4]\n\n# create a generator\n\u003e (x for x in [1, 2] if x % 2 == 0)\n\u003cgenerator object \u003cgenexpr\u003e at 0x10379ee10\u003e\n```\n\n### find\nThe `find` method returns the first occurence of an iterator that satisfies a condition\n\nYou can use the `next()` method combined with a map or list comprehension:\n```python\ndef is_even(x):\n    return x % 2 == 0\n    \n# using filter    \n\u003e even_num_it = filter(is_even, [1, 2, 3, 4])  \n\u003e next(even_num_it, None)\n2\n\n# using list comprehension\n\u003e even_num_it = (x for x in [1, 2, 3, 4] if x % 2 == 0)\n\u003e next(even_num_it, None)\n2\n```\n\nNote that the generator is evaluated lazily so next would not evaluate elements after the element is found. The second parameter of the\nnext function is the value to return if the iterator is empty \n\n### contains\nThe `contains` method returns `True` if an element is present in the iterable.\n\nIn Python you can use the `in` operator:\n```python\n\u003e 1 in [1, 2, 3]\nTrue\n```\n\n### exists\nThe `exists` method returns `True` if an element satisfies a condition.\n \nYou can use the `any()` method combined with a map or list comprehension:\n```python\n\u003e even_num_it = (x % 2 == 0 for x in [1, 2, 3, 4])\n\u003e any(even_num_it)\nTrue\n```\nany will return `True` as soon as it finds a `True` value from an iterable.\n \n### forall\nThe `forall` method returns `True` if all the elements of the iterable satisfy the condition.\n\nYou can use the `all` method combined with a map or list comprehension: \n```python\n\u003e even_num_it = (x % 2 == 0 for x in [1, 2, 3, 4])\n\u003e all(even_num_it)\nFalse\n```\n\n### flatten\nThe `flatten` method converts an iterable of iterable of elements into an iterable of elements.\n\nYou can use a list comprehension:\n```python\n\u003e source = [[1, 2], [3, 4]]\n\u003e [element for sub_list in source for element in sub_list]\n[1, 2, 3, 4]\n```\n\nor you can use the function `chain` from itertools:\n```python\n\u003e source = [[1, 2], [3, 4]]\n\u003e flat_gen = itertools.chain(*source)\n\u003e list(flat_gen)\n[1, 2, 3, 4]\n```\n\n\n### flatMap\nThe `flatMap` applies map and flatten.\nYou can use a list comprehension:\n```python\n\u003e def create_range(x):\n    return range(x, x + 10)\n\n# We want to do something like source.flatMap(create_range)\n\u003e source = [10, 20, 30]\n\u003e [elem for s_elem in source for elem in create_range(s_elem)]\n[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n 32, 33, 34, 35, 36, 37, 38, 39]\n```\n\nor you can use the function `chain` from itertools:\n```python\n\u003e source = [10, 20, 30]\n\u003e it = itertools.chain(*[create_range(s_elem) for s_elem in source])\n\u003e list(it)\n[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n 32, 33, 34, 35, 36, 37, 38, 39]\n``` \n\n### reduce\nThe `reduce` function aggregates all the elements of a list into one.\n  \nYou can use the `reduce` function:  \n```python\n\u003e source = [1, 2, 3]\n\u003e reduce(lambda x, y: x + y, source)\n6\n```\n\nThe first parameter of the `reduce` function is a function that accepts 2 parameters and returns the reduction of the 2 parameters.\nIn our case we simply implemented the `sum` function.\n\n### zipWithIndex\n\nThe function `zipWithIndex` applied to an iterable return an iterator of tuples `(index, element)`.\n \nYou can use the `enumerate` function:\n```python\n\u003e source = ['a', 'b', 'c']\n\u003e for index, element in enumerate(source):\n    print('%d: %s' % (index, element))\n0: a\n1: b\n2: c    \n```\n\n### take\n\nThe function `take` returns an iterator that contains the first n elements of an iterator.\n\nYou can use the function `islice` from the module `itertools` similar to the regular slice for a list:\n* `islice(source, end)` similar to `list[:end]`\n* `islice(source, start, end)` similar to `list[start:end]`\n* `islice(source, start, end, step)` similar to `list[start:end:step]`. Note that `step` must be a positive number unlike for a list.\n\n```python\n\u003e  from itertools import islice\n\u003e source = [1, 2, 3, 4, 5]\n\u003e res_iterator = islice(source, 4)\n\u003e print(list(res_iterator))\n[1, 2, 3, 4]\n\n\u003e res_iterator = islice(source, 0, 4)\n\u003e print(list(res_iterator))\n[1, 2, 3, 4]\n\n\u003e res_iterator = islice(source, 0, 4, 2)\n\u003e print(list(res_iterator))\n[1, 3]\n```\n\n### takeWhile\n\nThe function `takeWhile` returns an iterable that contains elements starting from the first one until they don't satisfy a condition.\n\nYou can use the function `takewhile` from the module `itertools`:\n\n```python\n\u003e from itertools import takewhile\n\u003e source = [1, 2, 3, 4, 5, 6]\n\u003e res_iterator = takewhile(lambda x: x \u003c 3, source)\n\u003e list(res_iterator)\n[1, 2]\n```\n\n### dropWhile\n\nThe function `dropWhile` returns an iterable that strips all the elements starting from the start until they don't satisfy a condition.\n\nYou can use the function `dropwhile` from the module `itertools`:\n```python\n\u003e from itertools import dropwhile\n\u003e source = [1, 2, 3, 4, 5, 6]\n\u003e res_iterator = dropwhile(lambda x: x \u003c 3, source)\n\u003e list(res_iterator)\n[3, 4, 5, 6]\n```\n\n### scanLeft\n\nThe function `accumulate` allows to do things like running sum:\n```python\n\u003e from itertools import accumulate\n\u003e source = [1, 2, 3, 4, 5, 6]\n\u003e res_iterator = accumulate(source, lambda a, b: a + b)\n\u003e list(res_iterator)\n[1, 3, 6, 10, 15, 21]\n```\n\n### zip\n\nThe function `zip` and izip` from `itertools` combines 2 iterable and create respectively a list and an iterator:\n```python\n\u003e zip([1, 2, 3], [4, 5, 6]\n[(1, 3), (2, 4), (3, 5)]\n\n\u003e from itertools import izip\n\u003e izip(iter([1,2,3]), [3,4,5])\n\u003citertools.izip at 0x102a96998\u003e\n```\n\n### groupBy\n\nThe function `groupBy` groups elements by a applying a function to all the elements of an iterator / iterable and grouping those with the same function result.\n\nIn Python, the `groupby` method provided in itertools only groups elements with the same function result that are contiguous.\nFor instance:\n```python\n\u003e list(groupby(iter([1, 3, 2, 4, 5]), lambda x: x % 2))  # we wrap with list so we can see the result\n[(1, \u003citertools._grouper at 0x107309610\u003e),\n (0, \u003citertools._grouper at 0x107309810\u003e),\n (1, \u003citertools._grouper at 0x107309a50\u003e)]\n```\nIn this case, 1 and 3 are grouped together since `x % 2 == 1`, then 2 and 4 and grouped together (`x % 2 == 0`) but then again 5 belongs to a new group which was\npreviously created.\n\nIn this case, since the grouping function is a modulo, sorting the list before grouping would have worked.\n\n### reverse\nThe `reverse` function reverses a sequence.\n\nIn Python, you can use the method `reversed`:\n```python\n\u003e reverse([1, 2, 3])\n\u003clistreverseiterator at 0x101f204d0\u003e\n\u003e reverse((1, 2, 3))\n\u003creversed at 0x101f20790\u003e\n```\n\n### head and headOption\nThe method `head` returns the first element of an iterable and `headOption` returns an option of the first element or None if the iterable is empty.\n\nPython does not have Option but we can have something that returns None if the iterable is empty. We can use the method `next`:\n```python\n\u003e l = [1, 2, 3]\n\u003e next(iter(l), None)\n1\n\u003e l = []\n\u003e next(iter(l), None)\nNone\n```\n\nOr an if statement::\n```python\n\u003e l = [1, 2, 3]\n\u003e l[0] if l else None\n1\n\u003e l = []\n\u003e l[0] if l else None\nNone\n```\n\n### last and lastOption\nThe method `last` returns the last element of an iterable and `lastOption` returns an option of the last element or None if the iterable is empty.\n```python\n\u003e l = [1, 2, 3]\n\u003e next(reversed(l), None)\n3\n\u003e l = []\n\u003e next(reversed(l), None)\nNone\n```\n\nThis method will only work for sequences (since reversed only work for sequences). You can also use if statement instead if you use sequences:\n```python\n\u003e l = [1, 2, 3]\n\u003e l[-1] if l else None\n3\n\u003e l = []\n\u003e l[-1] if l else None\nNone\n```\n\n### getOrElse\n\nThe function `getOrElse` returns a value held by an option or a default value if the option is None.\n\nThere is no option in Python but one can do something like:\n```python\n\u003e t = 5\n\u003e -1 if t is None else t\n5\n\u003e t = None\n\u003e -1 if t is None else t\n-1\n```\n\n### min and max\n\nThe function `min` and `max` returns respectively the minimum and maximum element of an iterable. In Python, you can do:\n```python\n\u003e min([3, 2, 1, 5, 4])\n1\n\u003e max([3, 2, 1, 5, 4])\n5\n```\n\n### minBy and maxBy\n\nThe function `minBy` and `maxBy` returns respectively the minimum and maximum element of an iterable according to the result of a function. In Python, you can\nuse the method `min` and `max` and pass the function as the `key` parameter:\n```python\n\u003e min([3, 2, 1, 5, 4], key=lambda x: 5 - x)\n5\n\u003e max([3, 2, 1, 5, 4], key=lambda x: 5 - x)\n1\n```\n\n### sort and sortBy\n\nThe function `sort` sorts an iterable and `sortBy` sorts an iterable using a function. In Python one can use the function `sorted` with the optional parameter `key` to sort\nusing a function:\n```python\n\u003e sorted([3, 1, 2])\n[1, 2, 3]\n\u003e sorted([3, 1, 2], key=lambda x: 3 - x)\n[3, 2, 1]\n```\n\n### sum\n\nThe function `sum` returns the sum of an iterable:\n```python\n\u003e sum([1, 2, 3])\n6\n```\n\n### union\n\nThe function `union` chains 2 iterables together. In Python one can use the function `chain` from itertools:\n```python\n\u003e from itertools import chain\n\u003e it = chain([1, 2, 3], [4, 5, 6])\n\u003e list(it)\n[1, 2, 3, 4, 5, 6]\n```\n\nIf you deal with sequences (list or tuples), you can use the `+` operator:\n```python\n\u003e [1, 2, 3] + [4, 5, 6]\n[1, 2, 3, 4, 5, 6]\n\u003e (1, 2, 3) + (4, 5, 6)\n(1, 2, 3, 4, 5, 6)\n```\n\n### slide\n\nThe function `slide` allows to create a sliding window. In Python you can do the followings:\n```python\n\u003e l = range(10)\n\u003e window_size = 3\n\u003e slides = [l[i : i + window_size] for i in xrange(len(l) - window_size + 1)]\n[[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7], [6, 7, 8], [7, 8, 9]]\n```\n\n### Set Operations\n\nYou can instantiate a new set as follows:\n```python\ns = {1, 2, 3} # does not work with Python 2.6\ns = set([1, 2, 3])\n```\n\nYou can use the following methods:\n* union\n* intersection\n* union\n* isdisjoint\n* issubset\n* issuperset\n\n### Dictionary Operations\n\n##### Transforming a dictionary into another dictionary\n\t\nYou can iterate on a dictionary using the `items()` method\n```python\n# good, works on Python 2.7+ but does not work on Python 2.6\nreverse_dictionary = {v: k for k, v in d.items()}\n\n# works on all versions of Python\nreverse_dictionary = dict((v, k) for k, v in d.items())\n```\n\nYou can also use `iteritems()` instead of `items()` if the dictionary is large.\n\n### case class\n\nYou can use a `namedtuple` to do that. For instance:\n```python\n\u003e from collections import namedtuple\n\u003e Person = namedtuple('Person', ['name', 'age'])\n\u003e john = Person('john', 25)\n\u003e john.name\n'john'\n\u003e john.age\n25\n```\n\nYou can also specify default arguments using `__new__.__defaults__`:\n```python\n\u003e from collections import namedtuple\n\u003e Person = namedtuple('Person', ['name', 'age'])\n\u003e Person.__new__.__defaults__ = ('John Doe', 99)\n\u003e john = Person('john')\n\u003e john.name\n'john'\n\u003e john.age\n99\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchimpler%2Fpython-functional-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchimpler%2Fpython-functional-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchimpler%2Fpython-functional-guide/lists"}