From caac5364fec3cb4fab400a17e0a4cb3d348dd686 Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Wed, 17 Aug 2022 18:12:42 +0800 Subject: [PATCH 01/15] add ipython to be the material for teaching --- ipythons/Strain_your_brain.ipynb | 898 +++++++++++++++++++++++++++++++ 1 file changed, 898 insertions(+) create mode 100644 ipythons/Strain_your_brain.ipynb diff --git a/ipythons/Strain_your_brain.ipynb b/ipythons/Strain_your_brain.ipynb new file mode 100644 index 00000000..066494c3 --- /dev/null +++ b/ipythons/Strain_your_brain.ipynb @@ -0,0 +1,898 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# What The F*** Python\n", + "reference: https://github.com/satwikkansal/wtfpython" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `Walrus` (:=)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a := 5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(a := 5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(a, b := 7, 10)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(a := 6, 9) == ((a := 6), 9)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "x = (a := 696, 9)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "x[0] is a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def some_func():\n", + " return 5\n", + "if a := some_func():\n", + " print(a)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "qq = 0\n", + "def some_funcqq():\n", + " global qq\n", + " qq += 1\n", + " return qq\n", + "\n", + "while ha := some_funcqq():\n", + " if ha == 5:\n", + " print(ha)\n", + " break" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"end part 1\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "jupyter": { + "outputs_hidden": true + } + }, + "source": [ + "### global vs nonlocal" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def level1():\n", + " v = 2\n", + " def closure():\n", + " v += 1\n", + " closure()\n", + " return v\n", + "\n", + "print(level1())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "v = 1\n", + "def level1():\n", + " v = 2\n", + " def closure():\n", + " nonlocal v\n", + " v += 1\n", + " closure()\n", + " return v\n", + "\n", + "print(level1())\n", + "print(v)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "v = 1\n", + "def level1():\n", + " v = 2\n", + " def closure():\n", + " global v\n", + " v += 1\n", + " closure()\n", + " return v\n", + "\n", + "print(level1())\n", + "print(v)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "v = 1\n", + "def level1():\n", + " v = 2\n", + " def closure():\n", + " nonlocal v\n", + " print(v)\n", + " closure()\n", + "level1()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "v = 1\n", + "def closure():\n", + " global v\n", + " print(v)\n", + "closure()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"end part 2\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### tricky string" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = \"some_string\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "id(\"some\" + \"_\" + \"string\") == id(a)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* CPython optimization" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = \"wtf!\"\n", + "b = \"wtf!\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "id(a) == id(b)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a, b = \"wtf!\", \"wtf!\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a is b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = \"wtf!\"; b = \"wtf!\"\n", + "a is b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* depend on python shell / ipython / as a script" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Output (< Python3.7 )\n", + "\n", + "```\n", + ">>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa'\n", + "True\n", + ">>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa'\n", + "False\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### chained operations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(False == False) in [False]\n", + "False == (False in [False])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "False == False in [False]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "True is False == False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "False is False is False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "False is False is False is False is not True is True" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Comparisons" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "-1 < 0 < 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(1 > 0) < 1\n", + "1 > (0 < 1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(int(True))\n", + "True + 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### don't use `is`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "[] is []" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "() is ()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a, b = 257, 257" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a is b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = 257\n", + "b = 257\n", + "print(a is b)\n", + "\n", + "a = 256\n", + "b = 256\n", + "a is b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When you start up python the numbers from -5 to 256 will be allocated. These numbers are used a lot, so it makes sense just to have them ready. \n", + "Quoting from https://docs.python.org/3/c-api/long.html \n", + "> The current implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you just get back a reference to the existing object. So it should be possible to change the value of 1. I suspect the behavior of Python, in this case, is undefined. :-)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The optimization depends on OS, platform, version of python, interpreter, file or not, compiling, etc. \n", + "**don't count on these operations !!**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Hash brownies" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_dict = {}\n", + "some_dict[5.5] = \"JavaScript\"\n", + "some_dict[5.0] = \"Ruby\"\n", + "some_dict[5] = \"Python\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_dict[5.5]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_dict[5.0]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_dict[5]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "complex_five = 5 + 0j\n", + "type(complex_five)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_dict[complex_five]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "key of dict is **equivalence, not identity**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(5 == 5.0 == 5 + 0j)\n", + "print(hash(5) == hash(5.0) == hash(5 + 0j))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_dict" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* python occupies 5.0 instead of 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Deep down, we're all the same." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class WTF: ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print( WTF() == WTF() )\n", + "print( WTF() is WTF() )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> tow different instance could not be equal" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hash(WTF()) == hash(WTF())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class WTF2(object):\n", + " def __init__(self): print(\"I\")\n", + " def __del__(self): print(\"D\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "id(WTF2()) == id(WTF2())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**lifetime**\n", + "1. create WTF2 and pass it to id\n", + "2. id get the reference number and return it\n", + "3. the scope of first WTF2 is out, so it would be destroyed\n", + "4. the next WTF2 would allocate from the same memory !!!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Disorder within order" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from collections import OrderedDict\n", + "\n", + "dictionary = dict()\n", + "dictionary[1] = 'a'; dictionary[2] = 'b';\n", + "\n", + "ordered_dict = OrderedDict()\n", + "ordered_dict[1] = 'a'; ordered_dict[2] = 'b';\n", + "\n", + "another_ordered_dict = OrderedDict()\n", + "another_ordered_dict[2] = 'b'; another_ordered_dict[1] = 'a';\n", + "\n", + "class DictWithHash(dict):\n", + " \"\"\"\n", + " A dict that also implements __hash__ magic.\n", + " \"\"\"\n", + " __hash__ = lambda self: 0\n", + "\n", + "class OrderedDictWithHash(OrderedDict):\n", + " \"\"\"\n", + " An OrderedDict that also implements __hash__ magic.\n", + " \"\"\"\n", + " __hash__ = lambda self: 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dictionary == ordered_dict" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dictionary == another_ordered_dict" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ordered_dict == another_ordered_dict" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> Equality tests between OrderedDict objects are order-sensitive and are implemented as list(od1.items())==list(od2.items())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "len({dictionary, ordered_dict, another_ordered_dict})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "set or dict would only accept hashable value to be the `key`\n", + "> only immutable objects are hashable" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "another_set = set()\n", + "another_set.add(ordered_dict)\n", + "another_ordered_dict in another_set\n", + "=> False" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Keep trying..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def some_func():\n", + " try:\n", + " return 'from_try'\n", + " finally:\n", + " return 'from_finally'\n", + "\n", + "def another_func(): \n", + " for _ in range(3):\n", + " try:\n", + " continue\n", + " finally:\n", + " print(\"Finally!\")\n", + "\n", + "def one_more_func():\n", + " try:\n", + " for i in range(3):\n", + " try:\n", + " 1 / i\n", + " except ZeroDivisionError:\n", + " # Let's throw it here and handle it outside for loop\n", + " raise ZeroDivisionError(\"A trivial divide by zero error\")\n", + " finally:\n", + " print(\"Iteration\", i)\n", + " break\n", + " except ZeroDivisionError as e:\n", + " print(f\"Zero division error occurred: {e}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_func()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "another_func()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "1 / 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "one_more_func()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. finally woule run out of `return, break or continue`\n", + "2. The caveat here is, if the finally clause executes a return or break statement, the temporarily saved exception is discarded." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " for i in range(3):\n", + " try:\n", + " 1 / i\n", + " except ZeroDivisionError:\n", + " raise ZeroDivisionError(\"A trivial divide by zero error\")\n", + " finally:\n", + " print(\"Iteration\", i)\n", + "except ZeroDivisionError as e:\n", + " print(f\"Zero division error occurred: {e}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.9.13" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From d1bf05b762da9dc9cd5d811c6502ef3472cbbb3f Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Wed, 17 Aug 2022 20:06:01 +0800 Subject: [PATCH 02/15] fix error example and add some examples --- ipythons/Strain_your_brain.ipynb | 101 ++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/ipythons/Strain_your_brain.ipynb b/ipythons/Strain_your_brain.ipynb index 066494c3..4f06fe27 100644 --- a/ipythons/Strain_your_brain.ipynb +++ b/ipythons/Strain_your_brain.ipynb @@ -757,10 +757,11 @@ "metadata": {}, "outputs": [], "source": [ + "ordered_dict = OrderedDictWithHash(ordered_dict)\n", + "another_ordered_dict = OrderedDictWithHash(another_ordered_dict)\n", "another_set = set()\n", "another_set.add(ordered_dict)\n", - "another_ordered_dict in another_set\n", - "=> False" + "another_ordered_dict in another_set" ] }, { @@ -866,6 +867,102 @@ " print(f\"Zero division error occurred: {e}\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### For what?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_string = \"wtf\"\n", + "some_dict = {}\n", + "for i, some_dict[i] in enumerate(some_string):\n", + " i = 10" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_dict" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "i, some_dict[i] = (0, 'w')\n", + "i, some_dict[i] = (1, 't')\n", + "i, some_dict[i] = (2, 'f')\n", + "some_dict" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Evaluation time discrepancy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "array = [1, 8, 15]\n", + "# A typical generator expression\n", + "gen = (x for x in array if array.count(x) > 0)\n", + "array = [2, 8, 22]\n", + "print(list(gen))\n", + "print(type(gen))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "array_1 = [1,2,3,4]\n", + "gen_1 = (x for x in array_1)\n", + "array_1 = [1,2,3,4,5]\n", + "\n", + "array_2 = [1,2,3,4]\n", + "gen_2 = (x for x in array_2)\n", + "array_2[:] = [1,2,3,4,5]\n", + "\n", + "print(list(gen_1))\n", + "\n", + "print(list(gen_2))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "array_3 = [1, 2, 3]\n", + "array_4 = [10, 20, 30]\n", + "gen = (i + j for i in array_3 for j in array_4)\n", + "\n", + "array_3 = [4, 5, 6]\n", + "array_4 = [400, 500, 600]\n", + "\n", + "print(list(gen))" + ] + }, { "cell_type": "code", "execution_count": null, From 5ebcb39ad3d88964e6be10089e23a58fde45a6ad Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Wed, 17 Aug 2022 20:09:00 +0800 Subject: [PATCH 03/15] rename to crippled_wtf.ipynb and put it irrelevant folder with wtf.ipynb --- ipythons/Strain_your_brain.ipynb => irrelevant/crippled_wtf.ipynb | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ipythons/Strain_your_brain.ipynb => irrelevant/crippled_wtf.ipynb (100%) diff --git a/ipythons/Strain_your_brain.ipynb b/irrelevant/crippled_wtf.ipynb similarity index 100% rename from ipythons/Strain_your_brain.ipynb rename to irrelevant/crippled_wtf.ipynb From 3b7482f6e5014f52cca745a399b82195d616d371 Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Thu, 18 Aug 2022 00:16:03 +0800 Subject: [PATCH 04/15] add more examples --- irrelevant/crippled_wtf.ipynb | 136 +++++++++++++++++++++++++++++++++- 1 file changed, 132 insertions(+), 4 deletions(-) diff --git a/irrelevant/crippled_wtf.ipynb b/irrelevant/crippled_wtf.ipynb index 4f06fe27..b81be630 100644 --- a/irrelevant/crippled_wtf.ipynb +++ b/irrelevant/crippled_wtf.ipynb @@ -901,6 +901,8 @@ "metadata": {}, "outputs": [], "source": [ + "del i\n", + "# the for-loop would be like\n", "i, some_dict[i] = (0, 'w')\n", "i, some_dict[i] = (1, 't')\n", "i, some_dict[i] = (2, 'f')\n", @@ -914,6 +916,26 @@ "### Evaluation time discrepancy" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import collections\n", + "def fun():\n", + " for i in range(4):\n", + " yield i\n", + "\n", + "print(type(fun))\n", + "print(type(fun()))\n", + "\n", + "gen = fun()\n", + "\n", + "print(f\"get item from generator: {list(gen)}\")\n", + "print(f\"after giving the number to list: {list(gen)}\")" + ] + }, { "cell_type": "code", "execution_count": null, @@ -924,8 +946,7 @@ "# A typical generator expression\n", "gen = (x for x in array if array.count(x) > 0)\n", "array = [2, 8, 22]\n", - "print(list(gen))\n", - "print(type(gen))" + "print(f\"should be {array} but is {list(gen)}\")" ] }, { @@ -935,14 +956,18 @@ "outputs": [], "source": [ "array_1 = [1,2,3,4]\n", + "print(id(array_1))\n", "gen_1 = (x for x in array_1)\n", "array_1 = [1,2,3,4,5]\n", + "print(id(array_1))\n", + "\n", + "print(list(gen_1))\n", "\n", "array_2 = [1,2,3,4]\n", + "print(id(array_2))\n", "gen_2 = (x for x in array_2)\n", "array_2[:] = [1,2,3,4,5]\n", - "\n", - "print(list(gen_1))\n", + "print(id(array_2))\n", "\n", "print(list(gen_2))" ] @@ -963,6 +988,109 @@ "print(list(gen))" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "first array_3 + second array_4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. In a generator expression, the in clause is evaluated at declaration time, but the conditional clause is evaluated at runtime.\n", + "2. [PEP-289](https://www.python.org/dev/peps/pep-0289/#the-details) \n", + " > Only the outermost for-expression is evaluated immediately, the other expressions are deferred until the generator is run.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "array = [1, 8, 15]\n", + "# A typical generator expression\n", + "gen = (x for x in array if print(f\"{array} has {x} ?\"))\n", + "array = [2, 8, 22]\n", + "list(gen)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### is not ... is not is (not ...)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "'something' is not None" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "'something' is (not None)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### A tic-tac-toe where X wins in the first attempt!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "row = [\"\"] * 3\n", + "board = [row] * 3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(board)\n", + "print(board[0])\n", + "print(board[0][0])\n", + "board[0][0] = \"X\"\n", + "board" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "board = [['']*3 for _ in range(3)]\n", + "board[0][0] = \"X\"\n", + "print(board)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* string is immutable and the row, list, is mutable.\n", + "* use comprehensions to initialize list, dict, etc." + ] + }, { "cell_type": "code", "execution_count": null, From 75529c6e031381fc53ca0a120f3f42051714db29 Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Mon, 22 Aug 2022 11:28:57 +0800 Subject: [PATCH 05/15] add two examples --- irrelevant/crippled_wtf.ipynb | 231 +++++++++++++++++++++++++++++++++- 1 file changed, 228 insertions(+), 3 deletions(-) diff --git a/irrelevant/crippled_wtf.ipynb b/irrelevant/crippled_wtf.ipynb index b81be630..dfb2c49c 100644 --- a/irrelevant/crippled_wtf.ipynb +++ b/irrelevant/crippled_wtf.ipynb @@ -982,8 +982,8 @@ "array_4 = [10, 20, 30]\n", "gen = (i + j for i in array_3 for j in array_4)\n", "\n", - "array_3 = [4, 5, 6]\n", - "array_4 = [400, 500, 600]\n", + "array_5 = [4, 5, 6]\n", + "array_6 = [400, 500, 600]\n", "\n", "print(list(gen))" ] @@ -1091,6 +1091,231 @@ "* use comprehensions to initialize list, dict, etc." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Schrödinger's variable *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "funcs = []\n", + "results = []\n", + "for x in range(7):\n", + " def some_func():\n", + " return x\n", + " funcs.append(some_func)\n", + " results.append(some_func()) # note the function call here\n", + "\n", + "funcs_results = [func() for func in funcs]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "funcs_results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "powers_of_x = [lambda x: x**i for i in range(10)]\n", + "[f(2) for f in powers_of_x]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import inspect\n", + "inspect.getclosurevars(funcs[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = 42\n", + "[func() for func in funcs]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "inspect.getclosurevars(funcs[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "funcs = []\n", + "for x in range(7):\n", + " def some_func(x=x):\n", + " return x\n", + " funcs.append(some_func)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "funcs_results = [func() for func in funcs]\n", + "funcs_results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "inspect.getclosurevars(funcs[0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The chicken-egg problem " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "isinstance(3, int)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "isinstance(type, object)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "isinstance(object, type)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class A: ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "isinstance(A, A)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "isinstance(type, type)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "isinstance(object, object)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "issubclass(int, object)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "issubclass(type, object)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "issubclass(object, type)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. everything is an object, which includes classes as well as their objects (instances)\n", + "2. type is metaclass\n", + "3. class type is the metaclass of class object, and every class (including type) has inherited directly or indirectly from object.\n", + "4. There is no real base class among object and type. The confusion in the above snippets is arising because we're thinking about these relationships (issubclass and isinstance) in terms of Python classes. `The relationship between object and type can't be reproduced in pure python.` To be more precise the following relationships can't be reproduced in pure Python,\n", + "\n", + " class A is an instance of class B, and class B is an instance of class A.\n", + " class A is an instance of itself.\n", + "\n", + "5. These relationships between object and type (both being instances of each other as well as themselves) exist in Python because of \"cheating\" at the implementation level." + ] + }, { "cell_type": "code", "execution_count": null, @@ -1115,7 +1340,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.13" + "version": "3.10.5" } }, "nbformat": 4, From b73b95e0ebfbf8975fc3289ac341efacf9f4d34d Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Sat, 27 Aug 2022 13:05:27 +0800 Subject: [PATCH 06/15] update examples --- irrelevant/crippled_wtf.ipynb | 397 ++++++++++++++++++++++++++++++++++ 1 file changed, 397 insertions(+) diff --git a/irrelevant/crippled_wtf.ipynb b/irrelevant/crippled_wtf.ipynb index dfb2c49c..9b6051d4 100644 --- a/irrelevant/crippled_wtf.ipynb +++ b/irrelevant/crippled_wtf.ipynb @@ -1316,6 +1316,403 @@ "5. These relationships between object and type (both being instances of each other as well as themselves) exist in Python because of \"cheating\" at the implementation level." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Subclass relationships" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from collections.abc import Hashable\n", + "\n", + "issubclass(list, object)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "issubclass(object, Hashable)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "issubclass(list, Hashable)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> A -> B \n", + "> A > C \n", + "> B > C ?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list.__subclasscheck__" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "object.__hash__" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list.__hash__ == None" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# 3.4, refer to https://www.naftaliharris.com/blog/python-subclass-intransitivity/\n", + "class Hashable(metaclass=ABCMeta):\n", + "\n", + " __slots__ = ()\n", + "\n", + " @abstractmethod\n", + " def __hash__(self):\n", + " return 0\n", + "\n", + " @classmethod\n", + " def __subclasshook__(cls, C): \n", + " if cls is Hashable:\n", + " for B in C.__mro__:\n", + " if \"__hash__\" in B.__dict__:\n", + " if B.__dict__[\"__hash__\"]:\n", + " return True\n", + " break\n", + " return NotImplemented" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* involving metaclasses, abstract classes, subclasschecks, and subclasshooks." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "### Methods equality and identity" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class SomeClass:\n", + " def method(self):\n", + " pass\n", + "\n", + " @classmethod\n", + " def classm(cls):\n", + " pass\n", + "\n", + " @staticmethod\n", + " def staticm():\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(SomeClass.method is SomeClass.method)\n", + "print(SomeClass.classm is SomeClass.classm)\n", + "print(SomeClass.classm == SomeClass.classm)\n", + "print(SomeClass.staticm is SomeClass.staticm)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "o1 = SomeClass()\n", + "o2 = SomeClass()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(o1.method == o2.method)\n", + "print(o1.method == o1.method)\n", + "print(o1.method is o1.method)\n", + "print(o1.classm is o1.classm)\n", + "print(o1.classm == o1.classm == o2.classm == SomeClass.classm)\n", + "print(o1.staticm is o1.staticm is o2.staticm is SomeClass.staticm)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "o1.method is o1.method" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "o1.classm" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Descriptor\n", + "\n", + "dic = [\"a\", \"b\", \"c\"]\n", + "\n", + "class DirectorySize:\n", + " def __get__(self, obj, objtype=None):\n", + " return len(obj.dirname)\n", + "\n", + "class Directory:\n", + "\n", + " size = DirectorySize() # Descriptor instance\n", + "\n", + " def __init__(self, dirname):\n", + " self.dirname = dirname # Regular instance attribute\n", + "g = Directory(dic)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "g.size" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dic.remove(\"b\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "g.size" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SomeClass.method" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "o1.classm" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SomeClass.classm" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "o1.staticm" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SomeClass.staticm" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> Having to create new \"method\" objects every time Python calls instance methods and having to modify the arguments every time in order to insert self affected performance badly. CPython 3.7 solved it by introducing new opcodes that deal with calling methods without creating the temporary method objects. This is used only when the accessed function is actually called, so the snippets here are not affected, and still generate methods :)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "o1_method1 = o1.method\n", + "o1_method2 = o1.method\n", + "print(id(o1_method1))\n", + "print(id(o1_method2))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(o1.method.__func__ is SomeClass.method)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### All-true-ation " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "all([True, True, True])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "all([])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "all([[]])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "all([[[]]])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# like\n", + "def all(iterable):\n", + " for element in iterable:\n", + " if not element:\n", + " return False\n", + " return True" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "all([]) = > not check and return True\n", + "all([[]]) = > check [], not [] => False\n", + "all([[[]]]) = > check [[]], not [[]] = > True\n", + "all(" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "not [[]]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "all([[[[[[]]]]]])" + ] + }, { "cell_type": "code", "execution_count": null, From c019b4153a829adffeeaa9d6cdf77cba5c32652d Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Sun, 28 Aug 2022 18:32:49 +0800 Subject: [PATCH 07/15] update to What's wrong with booleans? --- irrelevant/crippled_wtf.ipynb | 319 ++++++++++++++++++++++++++++++++++ 1 file changed, 319 insertions(+) diff --git a/irrelevant/crippled_wtf.ipynb b/irrelevant/crippled_wtf.ipynb index 9b6051d4..98709a2b 100644 --- a/irrelevant/crippled_wtf.ipynb +++ b/irrelevant/crippled_wtf.ipynb @@ -1713,6 +1713,325 @@ "all([[[[[[]]]]]])" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The surprising comma" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def f(x, y,):\n", + " print(x, y)\n", + "\n", + "def g(x=4, y=5,):\n", + " print(x, y)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def h(x, **kwargs,):\n", + " ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def h(*args,):\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "before 3.6 version, the tailing comma is syntax error in python" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Strings and the backslashes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"\\\"\")\n", + "print(r\"\\\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(r\"\\\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "r'\\'' == \"\\\\'\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. he backslash is used to escape special characters\n", + "2. use r'' to be `a raw string` literal\n", + "3. This means when a parser encounters a backslash in a raw string, it expects another character following it. And in our case (print(r\"\\\")), the backslash escaped the trailing quote, leaving the parser without a terminating quote (hence the SyntaxError). That's why backslashes don't work at the end of a raw string." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "r\"\\\\\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "r\"\\n\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(r\"\\\\\") # r\"\\\\\" would turn into \"\\\\\\\\\" and passe it to print" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### not knot!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = True\n", + "y = False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "not x == y" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x == not y" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. `==` operator has higher precedence than `not` operator in Python \n", + "2. `not x == y` is equivalent to `not (x == y)`\n", + "3. `x == not y` would be `(x == not) y`\n", + "4. The parser expected the `not` token to be a part of the `not in` operator\n", + "5. `not in` has same precedence as `==`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x not in == y" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x not == y" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x == not in y" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Half triple-quoted strings" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print('wtfpython''')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"wtfpython\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"\"\"wtfpython\") # print('''wtfpython')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"wtfpython\"\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"ab\" \"cd\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### What's wrong with booleans?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mixed_list = [False, 1.0, \"some_string\", 3, True, [], False]\n", + "integers_found_so_far = 0\n", + "booleans_found_so_far = 0\n", + "\n", + "for item in mixed_list:\n", + " if isinstance(item, int):\n", + " integers_found_so_far += 1\n", + " elif isinstance(item, bool):\n", + " booleans_found_so_far += 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "integers_found_so_far" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "booleans_found_so_far" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_bool = True\n", + "\"wtf\" * some_bool" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_bool = False\n", + "\"wtf\" * some_bool" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# < 3.*\n", + "def tell_truth():\n", + " True = False\n", + " if True == False:\n", + " print(\"I have lost faith in truth!\")\n", + "tell_truth()" + ] + }, { "cell_type": "code", "execution_count": null, From 8cfdf3b6366d1139951385bbb6d8c563376389b0 Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Fri, 2 Sep 2022 12:14:16 +0800 Subject: [PATCH 08/15] add an example to kill coroutine in executor and colon in list example --- irrelevant/crippled_wtf.ipynb | 242 +++++++++++++++++++++++++++++++++- 1 file changed, 240 insertions(+), 2 deletions(-) diff --git a/irrelevant/crippled_wtf.ipynb b/irrelevant/crippled_wtf.ipynb index 98709a2b..2145613a 100644 --- a/irrelevant/crippled_wtf.ipynb +++ b/irrelevant/crippled_wtf.ipynb @@ -1944,7 +1944,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"wtfpython\"\"\"\")" + "print(\"wtfpython\"\"\")" ] }, { @@ -1953,7 +1953,7 @@ "metadata": {}, "outputs": [], "source": [ - "\"ab\" \"cd\"" + "\"ab\" \"cd\" # \"ab\" + \"cd\"" ] }, { @@ -2032,6 +2032,244 @@ "tell_truth()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Future~" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import asyncio\n", + "import threading\n", + "import concurrent\n", + "import signal\n", + "import time\n", + "from enum import Enum, auto\n", + "\n", + "class action(Enum):\n", + " cancel = auto()\n", + " shutdown = auto()\n", + " signal = auto()\n", + "\n", + "def blocking():\n", + " print(f\"block: {threading.get_ident()}\")\n", + " time.sleep(5)\n", + " print(\"5s\")\n", + " time.sleep(8)\n", + " print(\"13s\")\n", + " time.sleep(2)\n", + " print(\"15s\")\n", + "\n", + "async def haha_proces(fut, exe, kill):\n", + " import subprocess\n", + " print(threading.get_ident())\n", + " print(\"haha go\")\n", + " await asyncio.sleep(10)\n", + " if kill == action.cancel:\n", + "\n", + " fut.cancel()\n", + " fut.set_exception(asyncio.TimeoutError)\n", + "\n", + " elif kill == action.shutdown:\n", + "\n", + " exe.shutdown(wait=True)\n", + "\n", + " elif kill == action.signal:\n", + "\n", + " for t in exe._threads:\n", + " print(f\"kill {t.ident}\")\n", + " signal.pthread_kill(t.ident, signal.SIGTERM)\n", + "\n", + " print(\"haha out\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "async def main(action: action):\n", + " print('Hello ...')\n", + " loop = asyncio.get_event_loop()\n", + " exe = concurrent.futures.ThreadPoolExecutor(max_workers=1, thread_name_prefix='asyncio')\n", + " future = loop.run_in_executor(exe, blocking)\n", + " task = loop.create_task(haha_proces(future, exe, action))\n", + " try:\n", + " await asyncio.gather(task, future, return_exceptions=True)\n", + " except Exception as e:\n", + " print(f\"{e}\")\n", + " print('End World!')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "await main(action.cancel)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "await main(action.shutdown)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "await main(action.signal)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def blocking():\n", + " def signal_handler(sig, frame):\n", + " import sys\n", + " sys.exit(0)\n", + " try:\n", + " signal.signal(signal.SIGINT, signal_handler)\n", + " except Exception as e:\n", + " print(f\"{e}\")\n", + " print(f\"block: {threading.get_ident()}\")\n", + " \n", + "await main(action.signal)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Colon in the List" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = [1,2,3,4,5,6,7,8]\n", + "a[0::3]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[0:3]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[0:5:2]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[-1::4]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[-1::-4]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[1::4]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[1:-3]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[::]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[1:]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[-3:-1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[-3:-8]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[5:2]" + ] + }, { "cell_type": "code", "execution_count": null, From 6e111932f5648975f291e353d7388d43d41a9170 Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Tue, 6 Sep 2022 11:33:18 +0800 Subject: [PATCH 09/15] add new examples :) --- irrelevant/crippled_wtf.ipynb | 418 ++++++++++++++++++++++++++++++++++ 1 file changed, 418 insertions(+) diff --git a/irrelevant/crippled_wtf.ipynb b/irrelevant/crippled_wtf.ipynb index 2145613a..f0de01ff 100644 --- a/irrelevant/crippled_wtf.ipynb +++ b/irrelevant/crippled_wtf.ipynb @@ -2270,6 +2270,424 @@ "a[5:2]" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Class attributes and instance attributes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class A:\n", + " x = 1\n", + "\n", + "class B(A):\n", + " pass\n", + "\n", + "class C(A):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A.x, B.x, C.x" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "B.x = 2\n", + "A.x, B.x, C.x" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(id(A.x), id(C.x))\n", + "A.x = 3\n", + "A.x, B.x, C.x" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(id(A.x), id(C.x))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = A()\n", + "print(a.x is a.__class__.x)\n", + "a.x += 1\n", + "print(a.x is a.__class__.x)\n", + "a.x, A.x" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class SomeClass:\n", + " some_var = 15\n", + " some_list = [5]\n", + " another_list = [5]\n", + " def __init__(self, x):\n", + " self.some_var = x + 1\n", + " self.some_list = self.some_list + [x]\n", + " self.another_list += [x]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_obj = SomeClass(420)\n", + "some_obj.some_list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_obj.another_list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "another_obj = SomeClass(111)\n", + "another_obj.some_list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "another_obj.another_list is SomeClass.another_list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "another_obj.another_list is some_obj.another_list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "another_obj.another_list" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* reassigned some_list by `=`, but reused, in-place modification, list by `+=`\n", + "* if the variable is immutable, it would copy the value and modify it with to the new object under `+=` operator." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### yielding None" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_iterable = ('a', 'b')\n", + "\n", + "def some_func(val):\n", + " return \"something\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "[(yield x) for x in some_iterable]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* 3.8+ does not allow yield inside list comprehension\n", + "* before 3.7, yield in list has bug and could not generate expected result." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Yielding from... return! *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def some_func(x):\n", + " if x == 3:\n", + " return [\"wtf\"]\n", + " else:\n", + " yield from range(x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list(some_func(3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> `yield from` is used to generate a generator from another generator" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def some_func(x):\n", + " if x == 3:\n", + " return [\"wtf\"]\n", + " else:\n", + " for i in range(x):\n", + " yield i" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list(some_func(3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> \"... return expr in a generator causes StopIteration(expr) to be raised upon exit from the generator.\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " next(some_func(3))\n", + "except StopIteration as e:\n", + " some_string = e.value\n", + "some_string" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Nan-reflexivity *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = float('inf')\n", + "b = float('nan')\n", + "c = float('-iNf') # These strings are case-insensitive\n", + "d = float('nan')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "c" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "float('some_other_string')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a == -c" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "None == None" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b == d" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "50 / a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a / a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "23 + b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = float('nan')\n", + "y = x / x\n", + "y is y # identity holds" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "y == y # equality fails of y" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "[y] == [y] # but the equality succeeds for the list containing y" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* `'inf'` and `'nan'` represent mathematical `\"infinity\"` and `\"not a number\"` respectively\n", + "![](https://i.stack.imgur.com/OZKP7.jpg)\n", + "* in IEEE 754, `nan` is not euqal to `nan`\n", + "* in collection like `list`, it would compare identity first and compare `value` or `__eq__` if the identity is not the same." + ] + }, { "cell_type": "code", "execution_count": null, From 1dabc5d3ddae8a28d8c1b3c1f48e0b2efdfaf3bd Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Wed, 7 Sep 2022 11:14:49 +0800 Subject: [PATCH 10/15] finished Section: Strain your brain --- irrelevant/crippled_wtf.ipynb | 353 +++++++++++++++++++++++++++++++++- 1 file changed, 352 insertions(+), 1 deletion(-) diff --git a/irrelevant/crippled_wtf.ipynb b/irrelevant/crippled_wtf.ipynb index f0de01ff..62740fda 100644 --- a/irrelevant/crippled_wtf.ipynb +++ b/irrelevant/crippled_wtf.ipynb @@ -2688,12 +2688,363 @@ "* in collection like `list`, it would compare identity first and compare `value` or `__eq__` if the identity is not the same." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Mutating the immutable!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_tuple = (\"A\", \"tuple\", \"with\", \"values\")\n", + "another_tuple = ([1, 2], [3, 4], [5, 6])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_tuple[2] = \"change this\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "another_tuple[2].append(1000)\n", + "another_tuple" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "another_tuple[2] += [99, 999]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "another_tuple" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> `__iadd__` is called by `+=` and it's like extend in list but it would return itself" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a_list = []\n", + "print(a_list.__iadd__([1,2]))\n", + "a_list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b_list = []\n", + "print(b_list.extend([1,2]))\n", + "b_list" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In conclusion: \n", + "```\n", + " a += b \n", + " => a = a.__iadd__(b)\n", + "``` \n", + "It would use assign operator in low level " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The disappearing variable from outer scope" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "e = 7\n", + "try:\n", + " raise Exception()\n", + "except Exception as e:\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(e)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " raise Exception()\n", + "except Exception as e:\n", + " try:\n", + " pass\n", + " finally:\n", + " del e" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* only delete in the scope" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def f(x):\n", + " del(x)\n", + " print(x)\n", + "\n", + "x = 5\n", + "y = [5, 4, 3]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "f(x)\n", + "f(y)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(x, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The mysterious key type conversion" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class SomeClass(str):\n", + " pass\n", + "\n", + "some_dict = {'s': 42}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "type(list(some_dict.keys())[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s = SomeClass('si')\n", + "some_dict[s] = 40\n", + "some_dict" + ] + }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "type(list(some_dict.keys())[0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> SomeClass inherits all methods from `str`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class SomeClass(str):\n", + " def __eq__(self, other):\n", + " return (\n", + " type(self) is SomeClass\n", + " and type(other) is SomeClass\n", + " and super().__eq__(other)\n", + " )\n", + "\n", + " __hash__ = str.__hash__\n", + "\n", + "some_dict = {'s':42}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> When we define a custom `__eq__`, Python stops automatically inheriting the \n", + "> `__hash__` method, so we need to define it as well" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s = SomeClass('s')\n", + "some_dict[s] = 40\n", + "some_dict" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "keys = list(some_dict.keys())\n", + "type(keys[0]), type(keys[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> SomeClass' 's' is not equal str's 's'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Let's see if you can guess this?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a, b = a[b] = {}, 5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`(target_list \"=\")+ (expression_list | yield_expression)`\n", + "1. target_list is `a, b = a[b]` and expression_list is `{}, 5`\n", + "2. calculate expression_list and unpack it into target_list from left to right\n", + "3. `circular reference`: the `{...}` in the output refers to the same object that a is already referencing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a, b = {}, 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "now, the target_list is a[b] and the expression_list is the result in the first manipulation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a[b] = a, b" + ] } ], "metadata": { From 6aa65579523900736c2ef3b7769ed470f864f6b9 Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Wed, 7 Sep 2022 11:37:11 +0800 Subject: [PATCH 11/15] fixed a typo --- irrelevant/crippled_wtf.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/irrelevant/crippled_wtf.ipynb b/irrelevant/crippled_wtf.ipynb index 62740fda..637b8989 100644 --- a/irrelevant/crippled_wtf.ipynb +++ b/irrelevant/crippled_wtf.ipynb @@ -2901,7 +2901,7 @@ "metadata": {}, "outputs": [], "source": [ - "s = SomeClass('si')\n", + "s = SomeClass('s')\n", "some_dict[s] = 40\n", "some_dict" ] @@ -3043,7 +3043,7 @@ "metadata": {}, "outputs": [], "source": [ - "a[b] = a, b" + "a[b] = (a, b)" ] } ], From 3f650983f88d0d1a3259cec8a2131d180b67a714 Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Tue, 13 Sep 2022 11:49:14 +0800 Subject: [PATCH 12/15] start to section two --- irrelevant/crippled_wtf.ipynb | 127 ++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/irrelevant/crippled_wtf.ipynb b/irrelevant/crippled_wtf.ipynb index 637b8989..8319a583 100644 --- a/irrelevant/crippled_wtf.ipynb +++ b/irrelevant/crippled_wtf.ipynb @@ -3045,6 +3045,133 @@ "source": [ "a[b] = (a, b)" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Section: Slippery Slopes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Modifying a dictionary while iterating over it" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = {0: None}\n", + "\n", + "for i in x:\n", + " del x[i]\n", + " x[i+1] = None\n", + " print(i)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "before 3.5 and 2.*, the answer would be 0, 1, 2 ... n. The n depends on the dict resize implementation. \n", + "After 3.6+, python would raise a exception on it." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Stubborn del operation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class SomeClass:\n", + " def __del__(self):\n", + " print(\"Deleted!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = SomeClass()\n", + "y = x\n", + "del x; del y" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = SomeClass()\n", + "y = x\n", + "del x" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "id_y = id(y)\n", + "y # ref += 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "del y\n", + "globals()['y']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from collections.abc import Iterable\n", + "key = list(globals().keys())\n", + "golbals = globals()\n", + "while key:\n", + " k = key.pop()\n", + " if id_y == id(golbals[k]):\n", + " print(f'{k}: {golbals[k]}')\n", + " del golbals[k]\n", + "del key; del golbals" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { From 32167c6eb766667e554b57f5cd0f5b5362a58109 Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Sun, 2 Oct 2022 23:42:55 +0800 Subject: [PATCH 13/15] finished Section: Slippery Slopes, but ignored some overlay parts --- irrelevant/crippled_wtf.ipynb | 800 +++++++++++++++++++++++++++++++++- 1 file changed, 798 insertions(+), 2 deletions(-) diff --git a/irrelevant/crippled_wtf.ipynb b/irrelevant/crippled_wtf.ipynb index 8319a583..d7f07856 100644 --- a/irrelevant/crippled_wtf.ipynb +++ b/irrelevant/crippled_wtf.ipynb @@ -130,7 +130,8 @@ "metadata": { "jupyter": { "outputs_hidden": true - } + }, + "tags": [] }, "source": [ "### global vs nonlocal" @@ -3159,12 +3160,807 @@ "del key; del golbals" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The out of scope variable" + ] + }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "a = 1\n", + "def some_func():\n", + " return a\n", + "\n", + "def another_func():\n", + " # global a\n", + " a += 1\n", + " return a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def some_closure_func():\n", + " a = 1\n", + " def some_inner_func():\n", + " return a\n", + " return some_inner_func()\n", + "\n", + "def another_closure_func():\n", + " a = 1\n", + " def another_inner_func():\n", + " # nonlocal a\n", + " a += 1\n", + " return a\n", + " return another_inner_func()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_func()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "another_func()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_closure_func()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "another_closure_func()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Deleting a list item while iterating" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list_1 = [1, 2, 3, 4]\n", + "list_2 = [1, 2, 3, 4]\n", + "list_3 = [1, 2, 3, 4]\n", + "list_4 = [1, 2, 3, 4]\n", + "\n", + "for idx, item in enumerate(list_1):\n", + " del item\n", + "\n", + "for idx, item in enumerate(list_2):\n", + " list_2.remove(item)\n", + "\n", + "for idx, item in enumerate(list_3[:]):\n", + " list_3.remove(item)\n", + "\n", + "for idx, item in enumerate(list_4):\n", + " list_4.pop(idx)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list_1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list_2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list_3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list_4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* del is remove reference, but list_1 and return of enumerate would refer to it. the reference count would be two.\n", + "* remove and pop could immediately remove item from list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for idx, item in enumerate(list_1):\n", + " list_1.remove(item)\n", + " print(list_1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```c\n", + "static PyObject *\n", + "enum_next(enumobject *en)\n", + "{\n", + " PyObject *next_index;\n", + " PyObject *next_item;\n", + " PyObject *result = en->en_result;\n", + " PyObject *it = en->en_sit;\n", + " PyObject *old_index;\n", + " PyObject *old_item;\n", + "\n", + " next_item = (*Py_TYPE(it)->tp_iternext)(it);\n", + " if (next_item == NULL)\n", + " return NULL;\n", + "\n", + " if (en->en_index == PY_SSIZE_T_MAX)\n", + " return enum_next_long(en, next_item);\n", + "\n", + " next_index = PyLong_FromSsize_t(en->en_index);\n", + " if (next_index == NULL) {\n", + " Py_DECREF(next_item);\n", + " return NULL;\n", + " }\n", + " en->en_index++;\n", + "\n", + " if (Py_REFCNT(result) == 1) {\n", + " Py_INCREF(result);\n", + " old_index = PyTuple_GET_ITEM(result, 0);\n", + " old_item = PyTuple_GET_ITEM(result, 1);\n", + " PyTuple_SET_ITEM(result, 0, next_index);\n", + " PyTuple_SET_ITEM(result, 1, next_item);\n", + " Py_DECREF(old_index);\n", + " Py_DECREF(old_item);\n", + " // bpo-42536: The GC may have untracked this result tuple. Since we're\n", + " // recycling it, make sure it's tracked again:\n", + " if (!_PyObject_GC_IS_TRACKED(result)) {\n", + " _PyObject_GC_TRACK(result);\n", + " }\n", + " return result;\n", + " }\n", + " result = PyTuple_New(2);\n", + " if (result == NULL) {\n", + " Py_DECREF(next_index);\n", + " Py_DECREF(next_item);\n", + " return NULL;\n", + " }\n", + " PyTuple_SET_ITEM(result, 0, next_index);\n", + " PyTuple_SET_ITEM(result, 1, next_item);\n", + " return result;\n", + "}\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lossy zip of iterators *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "numbers = list(range(7))\n", + "numbers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "first_three, remaining = numbers[:3], numbers[3:]\n", + "first_three, remaining" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "numbers_iter = iter(numbers)\n", + "list(zip(numbers_iter, first_three)) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list(zip(numbers_iter, remaining))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```python\n", + "def zip(*iterables):\n", + " sentinel = object()\n", + " iterators = [iter(it) for it in iterables] # unpack the iterables into iter\n", + " while iterators:\n", + " result = []\n", + " for it in iterators: # loop all iterators\n", + " elem = next(it, sentinel) # get the next value of the iter\n", + " if elem is sentinel: return # end the zip if any iter is empty\n", + " result.append(elem)\n", + " yield tuple(result)\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "numbers = list(range(7))\n", + "numbers_iter = iter(numbers)\n", + "list(zip(first_three, numbers_iter))\n", + "list(zip(remaining, numbers_iter))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Loop variables leaking out!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for x in range(7):\n", + " if x == 6:\n", + " print(x, ': for x inside loop')\n", + "print(x, ': x in global')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# This time let's initialize x first\n", + "x = -1\n", + "for x in range(7):\n", + " if x == 6:\n", + " print(x, ': for x inside loop')\n", + "print(x, ': x in global')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print([x for x in range(5)])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(f\"python3 would got {x=}, but python2 would got 4 instead\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* The differences in the output of Python 2.x and Python 3.x interpreters for list comprehension example can be explained by following change documented in What’s New In Python 3.0 changelog:\n", + "> \"List comprehensions no longer support the syntactic form [... for var in item1, item2, ...]. Use [... for var in (item1, item2, ...)] instead. Also, note that list comprehensions have different semantics: they are closer to syntactic sugar for a generator expression inside a list() constructor, and in particular, the loop control variables are no longer leaked into the surrounding scope.\"\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Name resolution ignoring class scope" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = 5\n", + "class SomeClass:\n", + " x = 17\n", + " y = (x for i in range(10)) # generator\n", + " @classmethod\n", + " def get(cls):\n", + " return (cls.x for i in range(10))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list(SomeClass.y)[0]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list(SomeClass.get())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = 5\n", + "class SomeClass:\n", + " x = 17\n", + " y = [x for i in range(10)] # comprehension\n", + " @staticmethod\n", + " def get():\n", + " return x" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SomeClass.y[0] # python3 => 5, python2 => 17" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Starting from Python 3.X, list comprehensions also have their own scope.\n", + "* A generator expression has its own scope.\n", + "* Scopes nested inside class definition ignore names bound at the class level." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SomeClass.get()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = 5\n", + "def get():\n", + " x = 6\n", + " return x\n", + "print(get())\n", + "x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> [refer to global and nonlocal](crippled_wtf.ipynb#global-vs-nonlocal) and [out of scope](crippled_wtf.ipynb#The-out-of-scope-variable)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Rounding like a banker *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "round(1.5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "round(2.5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "0.5.__round__()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since Python 3.0, round() uses `banker's rounding` where .5 fractions are rounded to the nearest even number. Not follow `IEEE 754`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "2.675.__round__(2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float. See [Floating Point Arithmetic: Issues and Limitations for more information](https://docs.python.org/3/tutorial/floatingpoint.html#tut-fp-issues)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "np.round_(2.5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.ceil(2.5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.floor(2.5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def round_(x: float):\n", + " ret = np.round_(x)\n", + " if ret < x and ret + 1/2 == x:\n", + " return np.ceil(x)\n", + " return ret" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "round_(2.5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "round_(1.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Needles in a Haystack *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "t = ('one', 'two')\n", + "for i in t:\n", + " print(i)\n", + "\n", + "t = ('one')\n", + "for i in t:\n", + " print(i)\n", + "\n", + "t = ()\n", + "print(t)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = \"python\"\n", + "b = \"javascript\"\n", + "assert a != b, \"Both languages are different\"\n", + "assert (a == b, \"Both languages are different\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> https://docs.python.org/3/reference/simple_stmts.html#assert \n", + "\n", + "the assert is statment, so do not use it like function" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### The other cases are trivial, please check https://github.com/satwikkansal/wtfpython#-needles-in-a-haystack-" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Splitsies *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "''.split(' ')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "''.split()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "' a '.split(' ')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> If sep is not specified or is None, a different splitting algorithm is applied: runs of consecutive whitespace are regarded as a single separator, and the result will contain no empty strings at the start or end if the string has leading or trailing whitespace. Consequently, splitting an empty string or a string consisting of just whitespace with a None separator returns []. If sep is given, consecutive delimiters are not grouped together and are deemed to delimit empty strings (for example, '1,,2'.split(',') returns ['1', '', '2']). Splitting an empty string with a specified separator returns ['']." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Wild imports *" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "if import with wildcard `*`, the invisible naming would not be imported.\n", + "```python\n", + "from module import *\n", + "_abc()\n", + "Traceback (most recent call last):\n", + " File \"\", line 1, in \n", + "NameError: name '_abc' is not defined\n", + "``` \n", + "but we could import the name like\n", + "```python\n", + "from module import _abc\n", + "_abc()\n", + "``` " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "we also could use `__all__` to restrict the import members.\n", + "```python\n", + "# module.py\n", + "__all__ = [`_abc`]\n", + "def _abc(): ...\n", + "def abc(): ...\n", + "```\n", + "the import would like\n", + "```python\n", + "from module import *\n", + "_abc()\n", + "abc()\n", + "Traceback (most recent call last):\n", + " File \"\", line 1, in \n", + "NameError: name 'abc' is not defined\n", + "```\n", + "However, we still could use `module.abc()` or `from module import abc` to get `abc`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### All sorted? *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = 7, 8, 9 # tuple\n", + "sorted(x) == x" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "y = reversed(x)\n", + "sorted(y) == sorted(y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. be aware the return value\n", + " * reversed return iter object\n", + " * sorted return list object\n", + "2. list compares to tuple always return `False` in Python" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Midnight time doesn't exist?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from datetime import datetime\n", + "\n", + "midnight = datetime(2018, 1, 1, 0, 0)\n", + "midnight_time = midnight.time()\n", + "\n", + "noon = datetime(2018, 1, 1, 12, 0)\n", + "noon_time = noon.time()\n", + "\n", + "if midnight_time:\n", + " print(\"Time at midnight is\", midnight_time)\n", + "\n", + "if noon_time:\n", + " print(\"Time at noon is\", noon_time)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "before 3.5, datetime(2018, 1, 1, 0, 0) would equal to empty object in if condition" + ] }, { "cell_type": "code", From 23044f1b7883028b88037c3e782acf1015675591 Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Mon, 3 Oct 2022 18:33:19 +0800 Subject: [PATCH 14/15] finished Section: The Hidden treasures! --- irrelevant/crippled_wtf.ipynb | 354 ++++++++++++++++++++++++++++++++++ 1 file changed, 354 insertions(+) diff --git a/irrelevant/crippled_wtf.ipynb b/irrelevant/crippled_wtf.ipynb index d7f07856..dc79e00d 100644 --- a/irrelevant/crippled_wtf.ipynb +++ b/irrelevant/crippled_wtf.ipynb @@ -3962,6 +3962,360 @@ "before 3.5, datetime(2018, 1, 1, 0, 0) would equal to empty object in if condition" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### goto, but why?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. `goto`: an April Fool's joke on 1st April 2004\n", + "2. `goto-label`: use new opcode and rearrage code flow\n", + "3. `goto-statement`: use new opcode and rearrage code flow \n", + "\n", + "the implementation is using frame control or opcode rewriten. \n", + "However, if you really want to use `goto`, the better way is using [`try-except`](https://docs.python.org/3/faq/design.html#why-is-there-no-goto) to do it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class label(Exception): pass # declare a label\n", + "\n", + "try:\n", + " if True: raise label() # goto label\n", + "except label: # where to goto\n", + " print('here')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import dis\n", + "def a(i):\n", + " print(i)\n", + " return i+1\n", + "q = dis.Bytecode(a)\n", + "print(q.dis())\n", + "# https://docs.python.org/3/library/dis.html" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Brace yourself!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "WTF, I like `C`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import braces" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Let's meet Friendly Language Uncle For Life" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import barry_as_FLUFL\n", + "# This is relevant to PEP-401 released on April 1, 2009 " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"Ruby\" != \"Python\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"a\" == \"b\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"Ruby\" <> \"Python\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It works well in an interactive environment, but could not run in file. Please use `eval` in file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import barry_as_FLUFL\n", + "print(eval('\"Ruby\" <> \"Python\"'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Even Python understands that love is complicated" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import this" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "love = this" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "love is not True or False\n", + "# love (is not) True or False" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Yes, it exists!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def does_exists_num(l, to_find):\n", + " for num in l:\n", + " if num == to_find:\n", + " print(\"Exists!\")\n", + " break\n", + " else:\n", + " print(\"Does not exist\")\n", + "does_exists_num([1, 2, 3, 4, 5], 4)\n", + "does_exists_num([1, 2, 3, 4, 5], 6)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " pass\n", + "except:\n", + " print(\"Exception occurred!!!\")\n", + "else:\n", + " print(\"Try block executed successfully...\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Ellipsis *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Ellipsis == ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "three_dimensional_array = np.arange(8).reshape(2, 2, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.array_equal(three_dimensional_array[..., 1], three_dimensional_array[:,:,1])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from typing import Tuple\n", + "def others(t: Tuple[str, ...]):\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Inpinity" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "infinity = float('infinity')\n", + "print(hash(infinity))\n", + "\n", + "print(hash(float('-inf')))\n", + "print(hash(float('inf')))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Interestingly, the hash of float('-inf') is \"-10⁵ x π\" in Python 3, whereas \"-10⁵ x e\" in Python 2." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Let's mangle" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Yo(object):\n", + " def __init__(self):\n", + " # Let's try something symmetrical this time\n", + " self.__honey = True\n", + " self.__honey__ = True\n", + " self.bro = True\n", + " def some_func(self):\n", + " return __variable" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "obj = Yo()\n", + "for i in obj.__dict__:\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "obj.some_func()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "_Yo__variable = \"Cool\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "obj.some_func()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> Also, if the mangled name is longer than 255 characters, truncation will happen." + ] + }, { "cell_type": "code", "execution_count": null, From 15486c56cb0d0172bcbf481131d4eea810ce15c4 Mon Sep 17 00:00:00 2001 From: sunnyanthony Date: Mon, 3 Oct 2022 19:37:24 +0800 Subject: [PATCH 15/15] update all examples into crippled_wtf.ipynb --- irrelevant/crippled_wtf.ipynb | 486 +++++++++++++++++++++++++++++++++- 1 file changed, 485 insertions(+), 1 deletion(-) diff --git a/irrelevant/crippled_wtf.ipynb b/irrelevant/crippled_wtf.ipynb index dc79e00d..30b65359 100644 --- a/irrelevant/crippled_wtf.ipynb +++ b/irrelevant/crippled_wtf.ipynb @@ -4316,12 +4316,496 @@ "> Also, if the mangled name is longer than 255 characters, truncation will happen." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Teleportation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "def energy_send(x):\n", + " # Initializing a numpy array\n", + " np.array([float(x)])\n", + "\n", + "def energy_receive():\n", + " # Return an empty numpy array\n", + " return np.empty((), dtype=np.float64).tolist()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "energy_send(123.456)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "energy_receive()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. numpy does not clear the memory before free\n", + "2. after creating empty array in numpy, it does not initial the memory.\n", + "> In `c`, this would teach us a lesson." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Let's make a giant string!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def add_string_with_plus_bad(iters):\n", + " s = \"\"\n", + " for i in range(iters):\n", + " s = s + \"x\" + \"y\" + \"z\"\n", + " assert len(s) == 3*iters\n", + "\n", + "def add_string_with_plus(iters):\n", + " s = \"\"\n", + " for i in range(iters):\n", + " s += \"xyz\"\n", + " assert len(s) == 3*iters\n", + "\n", + "def add_bytes_with_plus(iters):\n", + " s = b\"\"\n", + " for i in range(iters):\n", + " s += b\"xyz\"\n", + " assert len(s) == 3*iters\n", + "\n", + "def add_string_with_format(iters):\n", + " fs = \"{}\"*iters\n", + " s = fs.format(*([\"xyz\"]*iters))\n", + " assert len(s) == 3*iters\n", + "\n", + "def add_string_with_join(iters):\n", + " l = []\n", + " for i in range(iters):\n", + " l.append(\"xyz\")\n", + " s = \"\".join(l)\n", + " assert len(s) == 3*iters\n", + "\n", + "def convert_list_to_string(iters):\n", + " l = \"xyz\" * iters\n", + " s = \"\".join(l)\n", + " assert len(s) == 3*iters" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "use `%timeit` to get the runtime in ipython, and module `timeit` in python" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%timeit -n1000 add_string_with_plus_bad(1000)\n", + "%timeit -n1000 add_string_with_plus(1000)\n", + "%timeit -n1000 add_bytes_with_plus(1000)\n", + "%timeit -n1000 add_string_with_format(1000)\n", + "%timeit -n1000 add_string_with_join(1000)\n", + "%timeit -n1000 convert_list_to_string(1000)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Slowing down dict lookups *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_dict = {str(i): 1 for i in range(1_000_000)}\n", + "another_dict = {str(i): 1 for i in range(1_000_000)}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%timeit some_dict['5']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_dict[1] = 1\n", + "%timeit some_dict['5']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%timeit another_dict['5']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "another_dict[1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%timeit another_dict['5'] # before 3.x, it would be slower. not sure the x exactly would be." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* some operation would break the key-searching optimizing.\n", + " * \"str\" only would faster than generic search(`__eq__`)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Bloating instance dicts *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "\n", + "class SomeClass:\n", + " def __init__(self):\n", + " self.some_attr1 = 1\n", + " self.some_attr2 = 2\n", + " self.some_attr3 = 3\n", + " self.some_attr4 = 4\n", + "\n", + "\n", + "def dict_size(o):\n", + " return sys.getsizeof(o.__dict__)\n", + "\n", + "o1 = SomeClass()\n", + "o2 = SomeClass()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print (dict_size(o1))\n", + "print (dict_size(o2))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "del o1.some_attr1\n", + "print (dict_size(o1))\n", + "print (dict_size(o2))\n", + "dict_size(SomeClass())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "* CPython is able to reuse the same \"keys\" object in multiple dictionaries. This was added in PEP 412 with the motivation to reduce memory usage, specifically in dictionaries of instances - where keys (instance attributes) tend to be common to all instances.\n", + "* This optimization is entirely seamless for instance dictionaries, but it is disabled if certain assumptions are broken.\n", + "* Key-sharing dictionaries **do not support deletion**; if an instance attribute is deleted, the dictionary is \"unshared\", and key-sharing is **disabled** for all future instances of the same class.\n", + "* Additionaly, if the dictionary keys have been **resized** (because new keys are inserted), they are kept shared only if they are used by a exactly single dictionary (this allows adding many attributes in the `__init__` of the very first created instance, without causing an \"unshare\"). If **multiple instances exist when a resize happens**, key-sharing is **disabled** for all future instances of the same class: CPython can't tell if your instances are using the same set of attributes anymore, and decides to bail out on attempting to share their keys.\n", + "* **A small tip, if you aim to lower your program's memory footprint: don't delete instance attributes, and make sure to initialize all attributes in your `__init__`!**\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Minor Ones *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "++4" + ] + }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "3 --0-- 5 == 3 + 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "-- is + \n", + "-(-) => + \n", + "+(+) => + " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = 10\n", + "a -=- 1\n", + "a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "False ** False == True # => 0**0 == 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### `@` or `__matmul__` operator in 3.5+" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "np.array([2, 2, 2]) @ np.array([7, 8, 8])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Python uses 2 bytes for local variable storage in functions. In theory, this means that only 65536 variables can be defined in a function. However, python has a handy solution built in that can be used to store more than 2^16 variable names. The following code demonstrates what happens in the stack when more than 65536 local variables are defined (Warning: This code prints around 2^18 lines of text, so be prepared!):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import dis\n", + "exec(\"\"\"\n", + "def f():\n", + " \"\"\" + \"\"\"\n", + " \"\"\".join([\"X\" + str(x) + \"=\" + str(x) for x in range(2)]))\n", + "\n", + "f()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# dis.dis(f) <-- call it would print a lot of ops\n", + "...\n", + "65334 521626 EXTENDED_ARG 255\n", + " 521628 LOAD_CONST 65332 (65331)\n", + " 521630 EXTENDED_ARG 255\n", + " 521632 STORE_FAST 65331 (X65331)\n", + " ...\n", + "65541 523292 EXTENDED_ARG 1\n", + " 523294 EXTENDED_ARG 256\n", + " 523296 LOAD_CONST 65539 (65538)\n", + " 523298 EXTENDED_ARG 1\n", + " 523300 EXTENDED_ARG 256\n", + " 523302 STORE_FAST 65538 (X65538)\n", + " 523304 LOAD_CONST 0 (None)\n", + " 523306 RETURN_VALUE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import dis\n", + "exec(\"\"\"\n", + "def f():\n", + " \"\"\" + \"\"\"\n", + " \"\"\".join([\"X\" + str(x) + \"=\" + str(x) for x in range(5)]))\n", + "\n", + "f()\n", + "dis.dis(f)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### use multiple processes instead of thread\n", + "**Global Interpreter Lock**\n", + "1. this lock would be called before every c-level call. The only way to disable it is call.\n", + "2. The library sould use python api to create thread or add GIL in the thread to lock with GIL.\n", + "\n", + "Luckily, many potentially blocking or long-running operations, such as I/O, image processing, and NumPy number crunching, happen outside the GIL. Therefore it is only in multithreaded programs that spend a lot of time inside the GIL, interpreting CPython bytecode, that the GIL becomes a bottleneck. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```c\n", + "PyObject* abc(void){\n", + " ...\n", + " Py_BEGIN_ALLOW_THREADS\n", + " // release the GIL\n", + " Py_END_ALLOW_THREADS\n", + " return\n", + "}\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In cython, it still has GIL but able disable it.\n", + "**cython only**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with nogil:\n", + " # release the GIL here\n", + " ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# File some_file.py\n", + "import time\n", + "\n", + "print(\"wtfpython\", end=\"_\") # the buffer flush immediately only if it end with `/n`\n", + "time.sleep(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"wtfpython\", end=\"_\", flush=True)\n", + "time.sleep(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_str = \"wtfpython\"\n", + "some_list = ['w', 't', 'f', 'p', 'y', 't', 'h', 'o', 'n']\n", + "print(some_list is some_list[:]) # False expected because a new object is created.\n", + "print(some_str is some_str[:]) # True because strings are immutable, so making a new object is of not much use.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "'abc'.count('') == 4" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def count(s, sub):\n", + " result = 0\n", + " for i in range(len(s) + 1 - len(sub)):\n", + " result += (s[i:i + len(sub)] == sub)\n", + " return result" + ] } ], "metadata": {