
    
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
            
{"version":"https:\/\/jsonfeed.org\/version\/1","title":"mathspp.com feed","home_page_url":"https:\/\/mathspp.com\/blog\/tags\/repl","feed_url":"https:\/\/mathspp.com\/blog\/tags\/repl.json","description":"Stay up-to-date with the articles on mathematics and programming that get published to mathspp.com.","author":{"name":"Rodrigo Gir\u00e3o Serr\u00e3o"},"items":[{"title":"TIL #139 \u2013 Multiline input in the REPL","date_published":"2026-03-02T15:15:00+01:00","id":"https:\/\/mathspp.com\/blog\/til\/multiline-input-in-the-repl","url":"https:\/\/mathspp.com\/blog\/til\/multiline-input-in-the-repl","content_html":"<p>Today I learned how to do multiline input in the REPL using an uncommon combination of arguments for the built-in <code>open<\/code>.<\/p>\n\n<p>A while ago <a href=\"\/blog\/til\/020\">I learned I could use <code>open(0)<\/code> to open standard input<\/a>.\nThis unlocks a neat trick that allows you to do multiline input in the REPL:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; msg = open(0).read()\nHello,\nworld!\n^D\n&gt;&gt;&gt; msg\n'Hello,\\nworld!\\n'<\/code><\/pre>\n<p>The cryptic <code>^D<\/code> is <kbd>Ctrl<\/kbd>+<kbd>D<\/kbd>, which means EOF on Unix systems.\nIf you're on Windows, use <kbd>Ctrl<\/kbd>+<kbd>Z<\/kbd>.<\/p>\n<p>The problem is that if you try to use <code>open(0).read()<\/code> again to read more multiline input, you get an exception:<\/p>\n<pre><code class=\"language-py\">OSError: [Errno 9] Bad file descriptor<\/code><\/pre>\n<p>That's because, when you finished reading the first time around, Python closed the file descriptor <code>0<\/code>, so you can no longer use it.<\/p>\n<p>The fix is to set <code>closefd=False<\/code> when you use the built-in <code>open<\/code>.\nWith the parameter <code>closefd<\/code> set to <code>False<\/code>, the underlying file descriptor isn't closed and you can reuse it:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; msg1 = open(0, closefd=False).read()\nHello,\nworld!\n^D\n&gt;&gt;&gt; msg1\n'Hello,\\nworld!\\n'\n\n&gt;&gt;&gt; msg2 = open(0, closefd=False).read()\nGoodbye,\nworld!\n^D\n&gt;&gt;&gt; msg2\n'Goodbye,\\nworld!\\n'<\/code><\/pre>\n<p>By using <code>open(0, closefd=False)<\/code>, you can read multiline input in the REPL <em>repeatedly<\/em>.<\/p>","summary":"Today I learned how to do multiline input in the REPL using an uncommon combination of arguments for the built-in open.","date_modified":"2026-03-02T16:21:46+01:00","tags":["repl","programming","python"],"image":"\/user\/pages\/02.blog\/04.til\/139.multiline-input-in-the-repl\/thumbnail.webp"},{"title":"TIL #123 \u2013 The appearing built-in","date_published":"2025-05-06T22:45:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/the-appearing-builtin","url":"https:\/\/mathspp.com\/blog\/til\/the-appearing-builtin","content_html":"<p>Today I learned that the module <code>builtins<\/code> grows dynamically in the REPL.<\/p>\n\n<h2 id=\"the-appearing-built-in\">The appearing built-in<a href=\"#the-appearing-built-in\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>After <a href=\"https:\/\/bsky.app\/profile\/klaus.seistrup.dk\/post\/3loj3oimjj42n\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">some back and forth on BlueSky<\/a>, I tripped on some funky behaviour in the REPL:<\/p>\n<pre><code class=\"language-pycon\">## Fresh new REPL, Python 3.13:\n&gt;&gt;&gt; import builtins\n&gt;&gt;&gt; len(dir(builtins))\n159\n&gt;&gt;&gt; len(dir(builtins))\n160\n&gt;&gt;&gt; len(dir(builtins))\n160<\/code><\/pre>\n<p>What the heck is going on?\nWhy did the module <code>builtins<\/code> grow in size between the two calculations?!<\/p>\n<p>I restarted the REPL and tried something else:<\/p>\n<pre><code class=\"language-pycon\">## Fresh new REPL, Python 3.13:\n&gt;&gt;&gt; import builtins\n&gt;&gt;&gt; print(dir(builtins))\n[ ... ]\n&gt;&gt;&gt; print(dir(builtins))\n[ ... ]<\/code><\/pre>\n<p>I printed the contents of the module <code>builtins<\/code> twice in a row and they were exactly the same...\nThen, I checked, and the length of the module <code>builtins<\/code> was still 159:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; len(dir(builtins))\n159<\/code><\/pre>\n<p>But then I checked again, and it grew again:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; len(dir(builtins))\n160<\/code><\/pre>\n<p>For a second I was left wondering what sort of magic trick the built-in <code>len<\/code> must be playing, since it looks like it's making the module <code>builtins<\/code> grow another member...\nBut then I printed the contents of the module again and I found the culprit after using a text diff tool online:<\/p>\n<figure class=\"image-caption\"><img title=\"The name `_` appears magically.\" alt='A screenshot of a text diff comparison where the text on the right shows that the name \"_\" is new.' src=\"\/user\/pages\/02.blog\/04.til\/123.the-appearing-builtin\/_diff.webp\"><figcaption class=\"\">The name `_` appears magically.<\/figcaption><\/figure>\n<p>That's when it hit me: <a href=\"\/blog\/pydonts\/usages-of-underscore#recovering-last-result-in-the-session\">the REPL has a special name <code>_<\/code> that refers to the result of the last operation<\/a>.<\/p>\n<p>Importing the module isn't enough to make it show up because it's a statement and statements don't produce a value.\nSimilarly, the code <code>print(dir(builtins))<\/code> also isn't enough because printing \u201cdoesn't return a result\u201d, but when I run <code>len(dir(builtins))<\/code>, the length is saved in <code>_<\/code>.<\/p>\n<p>But why is this variable in the module <code>builtins<\/code> if other variables aren't..?<\/p>\n<p>I am not entirely sure, but my guess is that this special <code>_<\/code> isn't a regular variable!\nYou can assign to <code>_<\/code> and it will \u201coverwrite\u201d the other value:<\/p>\n<pre><code class=\"language-pycon\">## Fresh new REPL:\n&gt;&gt;&gt; 1 + 2\n3\n&gt;&gt;&gt; _\n3\n&gt;&gt;&gt; _ = 73\n&gt;&gt;&gt; print(_)\n73<\/code><\/pre>\n<p>But it's not really overwriting the previous value...\nIt's actually shadowing the other one!\nHere's proof:<\/p>\n<pre><code class=\"language-pycon\">## Fresh new REPL:\n&gt;&gt;&gt; 1 + 2\n3\n&gt;&gt;&gt; _\n3\n&gt;&gt;&gt; _ = 73\n&gt;&gt;&gt; print(_)\n73\n&gt;&gt;&gt; import builtins\n&gt;&gt;&gt; builtins._\n3\n&gt;&gt;&gt; globals()[\"_\"]\n73<\/code><\/pre>\n<p>Fun, right?<\/p>","summary":"Today I learned that the module `builtins` grows dynamically in the REPL.","date_modified":"2025-10-20T22:34:56+02:00","tags":["programming","python","repl"],"image":"\/user\/pages\/02.blog\/04.til\/123.the-appearing-builtin\/thumbnail.webp"},{"title":"TIL #103 \u2013 debugging the new Python REPL with trace and PYREPL_TRACE.","date_published":"2024-07-13T19:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/debugging-the-new-python-repl-with-trace-and-pyrepl-trace","url":"https:\/\/mathspp.com\/blog\/til\/debugging-the-new-python-repl-with-trace-and-pyrepl-trace","content_html":"<p>Today I learned how to debug the new Python REPL with <code>_pyrepl.trace<\/code> and the environment variable <code>PYREPL_TRACE<\/code>.<\/p>\n\n<h2 id=\"debugging-the-new-python-repl-with-trace-and-pyrepl-trace\">Debugging the new Python REPL with <code>trace<\/code> and <code>PYREPL_TRACE<\/code>\n<a href=\"#debugging-the-new-python-repl-with-trace-and-pyrepl-trace\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>As of Python 3.13, the Python REPL is written <em>in Python<\/em>.\nThis means that if you are debugging the REPL and add a call to <code>print<\/code> in the code for the REPL, and then run the REPL, the debugging prints will show up in the REPL, in the middle of the thing you are trying to debug.\nThis can get quite confusing.<\/p>\n<p>To help alleviate this issue, the REPL includes a short submodule <code>trace<\/code> that implements the function <code>trace<\/code>, which can be used for debugging.\nIt is similar to the function <code>print<\/code>, but instead of writing to the console it will write to a file.<\/p>\n<p>The environment variable <code>PYREPL_TRACE<\/code> can then be used to set the path to the file to where <code>trace.trace<\/code> writes.\nIn practice, what I do (thanks, \u0141ukasz) is I have two terminals next to each other, run <code>tail -f PATH_TO_FILE<\/code> in one, and run <code>PYREPL_TRACE=PATH_TO_FILE python<\/code> in the other, and this opens the REPL and prints the tracing live to my second terminal window.<\/p>\n<p>If you have Python 3.13 installed, you can try this out for yourself:<\/p>\n<figure class=\"image-caption\"><img title=\"GIF demo of the tracing functionality.\" alt=\"Demo of the live debugging made possible by the submodule `trace` and the environment variable `PYREPL_TRACE`.\" src=\"\/user\/pages\/02.blog\/04.til\/103.debugging-the-new-python-repl-with-trace-and-pyrepl-trace\/_demo.gif?decoding=auto&amp;fetchpriority=auto\"><figcaption class=\"\">GIF demo of the tracing functionality.<\/figcaption><\/figure>","summary":"Today I learned how to debug the new Python REPL with `_pyrepl.trace` and the environment variable `PYREPL_TRACE`.","date_modified":"2025-10-20T22:34:56+02:00","tags":["programming","python","repl"],"image":"\/user\/pages\/02.blog\/04.til\/103.debugging-the-new-python-repl-with-trace-and-pyrepl-trace\/thumbnail.webp"},{"title":"TIL #102 \u2013 ctrl+left and ctrl+right not working in the Python REPL on MacOS","date_published":"2024-07-13T18:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/ctrl-left-and-ctrl-right-not-working-in-the-python-repl-on-macos","url":"https:\/\/mathspp.com\/blog\/til\/ctrl-left-and-ctrl-right-not-working-in-the-python-repl-on-macos","content_html":"<p>Today I learned how to fix an issue with <kbd>Ctrl<\/kbd>+<kbd>left<\/kbd> and <kbd>Ctrl<\/kbd>+<kbd>right<\/kbd> not working in the new Python REPL on MacOS.<\/p>\n\n<h2 id=\"ctrl-left-and-ctrl-right-not-working-in-the-python-repl-on-macos\">\n<kbd>Ctrl<\/kbd>+<kbd>left<\/kbd> and <kbd>Ctrl<\/kbd>+<kbd>right<\/kbd> not working in the Python REPL on MacOS<a href=\"#ctrl-left-and-ctrl-right-not-working-in-the-python-repl-on-macos\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The (new) Python REPL (3.13+) has <em>many<\/em> useful keyboard shortcuts and two of them are <kbd>Ctrl<\/kbd>+<kbd>left<\/kbd> and <kbd>Ctrl<\/kbd>+<kbd>right<\/kbd>, which are used to navigate the cursor by skipping to the beginning\/end of words, as the GIT below shows:<\/p>\n<figure class=\"image-caption\"><img title=\"GIF showing the keybindings in action.\" alt=\"Animation showing how ctrl+left and ctrl+right work on the Python REPL, jumping around words.\" src=\"\/user\/pages\/02.blog\/04.til\/102.ctrl-left-and-ctrl-right-not-working-in-the-python-repl-on-macos\/_keybinding.gif?decoding=auto&amp;fetchpriority=auto\"><figcaption class=\"\">GIF showing the keybindings in action.<\/figcaption><\/figure>\n<p>On MacOS, the keybindings were not working at all.\nWith the help of the new REPL trace functionality, we found out they weren't even making it to Python!<\/p>\n<p>After lots of digging, we found out what the issue was: MacOS was hijacking the two keybindings <kbd>Ctrl<\/kbd>+<kbd>left<\/kbd> and <kbd>Ctrl<\/kbd>+<kbd>right<\/kbd> for spaces-related shortcuts.\nTo turn those off, go to Settings &gt; Keyboard Shortcuts &gt; Mission Control &gt; Mission Control dropdown &gt; Untick \u201cMove left a space\u201d and \u201cMove right a space\u201d.<\/p>\n<p><img alt=\"Turning off the MacOS settings that hijack the keybidings to jump words on the Python REPL.\" src=\"\/user\/pages\/02.blog\/04.til\/102.ctrl-left-and-ctrl-right-not-working-in-the-python-repl-on-macos\/_settings.gif?decoding=auto&amp;fetchpriority=auto\"><\/p>","summary":"Today I learned how to fix an issue with Ctrl+left and Ctrl+right not working in the new Python REPL on MacOS.","date_modified":"2025-10-20T22:34:56+02:00","tags":["programming","python","repl"],"image":"\/user\/pages\/02.blog\/04.til\/102.ctrl-left-and-ctrl-right-not-working-in-the-python-repl-on-macos\/thumbnail.webp"}]}
