
    
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
    
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
            
{"version":"https:\/\/jsonfeed.org\/version\/1","title":"mathspp.com feed","home_page_url":"https:\/\/mathspp.com\/blog","feed_url":"https:\/\/mathspp.com\/blog.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":"Python quiz: EuroPython 2026 edition","date_published":"2026-07-21T17:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/python-quiz-europython-2026-edition","url":"https:\/\/mathspp.com\/blog\/python-quiz-europython-2026-edition","content_html":"<p>Replay the EuroPython 2026 Python quiz.<\/p>\n\n<script src=\"\/user\/themes\/myquark\/js\/quiz.js\"><\/script><link rel=\"stylesheet\" href=\"\/user\/themes\/myquark\/css\/quiz-custom.css\"><p>These are the questions asked during <a href=\"https:\/\/ep2026.europython.eu\/session\/python-quiz\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">the EuroPython 2026 quiz<\/a>.\nThey will test your knowledge of the Python language, the community, and of EuroPython 2026.\nSince we were celebrating 25 years of EuroPython at EuroPython 2026, some questions also touched on that theme.\n(Unless explicitly stated, questions refer to CPython 3.14.)<\/p>\n<div class=\"notices yellow\">\n<p>Note that the version of the quiz presented here is less interactive than the one presented at the conference.<\/p>\n<\/div>\n<h2 id=\"questions\">Questions<a href=\"#questions\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<div class=\"quiz-question\" data-correct=\"c\">\n  <div class=\"question-text\"><p>In 25 years of conference, which of these European cities never hosted EuroPython?<\/p><\/div>\n\n  <div>\n<p><img alt=\"A photograph of the city that never hosted EuroPython.\" src=\"\/user\/pages\/02.blog\/python-quiz-europython-2026-edition\/_lisbon.webp\"><\/p>\n<\/div>\n\n  <ul class=\"choices\"><li data-option=\"a\">Bilbao<\/li>\n    <li data-option=\"b\">Birmingham<\/li>\n    <li data-option=\"c\">Lisbon<\/li>\n    <li data-option=\"d\">Prague<\/li>\n  <\/ul><p class=\"feedback\"><\/p>\n<\/div>\n<div class=\"quiz-question\" data-correct=\"b\">\n  <div class=\"question-text\"><p>This year's conference programme has it all. This quiz. Talks. Lightning talks. Tutorials. Summits. Open spaces. Talks. And posters during lunch breaks. How many posters are scheduled to be presented at EP 2026?<\/p><\/div>\n\n  <ul class=\"choices\"><li data-option=\"a\">4<\/li>\n    <li data-option=\"b\">6<\/li>\n    <li data-option=\"c\">12<\/li>\n    <li data-option=\"d\">15<\/li>\n  <\/ul><p class=\"feedback\"><\/p>\n<\/div>\n<div class=\"quiz-question\" data-correct=\"a\">\n  <div class=\"question-text\"><p>Which of the following Python-related projects has the FEWEST stars on GitHub?<\/p><\/div>\n\n  <ul class=\"choices\"><li data-option=\"a\">CPython<\/li>\n    <li data-option=\"b\">Django<\/li>\n    <li data-option=\"c\">FastAPI<\/li>\n    <li data-option=\"d\">uv<\/li>\n  <\/ul><p class=\"feedback\"><\/p>\n<\/div>\n<div class=\"quiz-question\" data-correct=\"c\">\n  <div class=\"question-text\"><p>The Python repo has over 130,000 commits made by more than 3,500 contributors over the past 35+ years. The Python core developers are the people with permissions to commit directly to the CPython GitHub repo and plenty of them were at the conference. Out of the following 4 core devs, who were all at the conference, who's made the fewest commits?<\/p><\/div>\n\n  <ul class=\"choices\"><li data-option=\"a\">Guido van Rossum, the creator of Python<\/li>\n    <li data-option=\"b\">Hugo van Kemenade, Python 3.14 and 3.15 release manager<\/li>\n    <li data-option=\"c\">&#321;ukasz Langa, Python Developer in Residence for ~5 years<\/li>\n    <li data-option=\"d\">Pablo Galindo Salgado, Python 3.10 and 3.11 release manager<\/li>\n  <\/ul><p class=\"feedback\"><\/p>\n<\/div>\n<div class=\"quiz-question\" data-correct=\"11309\">\n  <div class=\"question-text\"><p>Speaking of commits, how many commits did Guido van Rossum make?<\/p><\/div>\n\n  <div>\n<p><img alt=\"A screenshot of Guido's contribution graph without any numbers.\" src=\"\/user\/pages\/02.blog\/python-quiz-europython-2026-edition\/_guido.webp\"><\/p>\n<\/div>\n\n  <form class=\"exact-answer\" novalidate>\n    <input type=\"number\" inputmode=\"numeric\" required><button type=\"submit\">Check<\/button>\n  <\/form>\n  <p class=\"feedback\"><\/p>\n<\/div>\n<div class=\"quiz-question\" data-correct=\"c\">\n  <div class=\"question-text\"><p>Since we're celebrating 25 years of EuroPython, which of the following expressions does not evaluate to 25?<\/p><\/div>\n\n  <ul class=\"choices\"><li data-option=\"a\"><code>0x19<\/code><\/li>\n    <li data-option=\"b\"><code>0b11001<\/code><\/li>\n    <li data-option=\"c\"><code>0o33<\/code><\/li>\n    <li data-option=\"d\"><code>25<\/code><\/li>\n  <\/ul><p class=\"feedback\"><\/p>\n<\/div>\n<div class=\"quiz-question\" data-correct=\"a\">\n  <div class=\"question-text\"><p>3.15 comes with two new built-in functions. Before that, the previous Python version that got new built-ins was 3.10, with also TWO new built-ins. What two built-ins were introduced in 3.10?<\/p><\/div>\n\n  <div>\n<p><img alt=\"A screenshot of all Python built-in functions in 3.15\" src=\"\/user\/pages\/02.blog\/python-quiz-europython-2026-edition\/_functions.webp\"><\/p>\n<\/div>\n\n  <ul class=\"choices\"><li data-option=\"a\">\n<code>aiter<\/code> and <code>anext<\/code>\n<\/li>\n    <li data-option=\"b\">\n<code>breakpoint<\/code> and <code>compile<\/code>\n<\/li>\n    <li data-option=\"c\">\n<code>frozendict<\/code> and <code>sentinel<\/code>\n<\/li>\n    <li data-option=\"d\">\n<code>frozenset<\/code> and <code>memoryview<\/code>\n<\/li>\n  <\/ul><p class=\"feedback\"><\/p>\n<\/div>\n<div class=\"quiz-question\" data-correct=\"a\">\n  <div class=\"question-text\"><p>What's printed by the second print if you run this code?<\/p><\/div>\n\n  <div>\n<p><img alt=\"A screenshot of a snippet of code caching a generator\" src=\"\/user\/pages\/02.blog\/python-quiz-europython-2026-edition\/_cached_generator.webp\"><\/p>\n<\/div>\n\n  <ul class=\"choices\"><li data-option=\"a\"><code>0<\/code><\/li>\n    <li data-option=\"b\"><code>285<\/code><\/li>\n    <li data-option=\"c\"><code>KeyError<\/code><\/li>\n    <li data-option=\"d\"><code>ValueError<\/code><\/li>\n  <\/ul><p class=\"feedback\"><\/p>\n<\/div>\n<div class=\"quiz-question\" data-correct=\"11309\">\n  <div class=\"question-text\"><p>By the way, speaking of commits, do you still remember how many commits Guido van Rossum made?<\/p><\/div>\n\n  <div>\n<p><img alt=\"A screenshot of Guido's contribution graph without any numbers.\" src=\"\/user\/pages\/02.blog\/python-quiz-europython-2026-edition\/_guido.webp\"><\/p>\n<\/div>\n\n  <form class=\"exact-answer\" novalidate>\n    <input type=\"number\" inputmode=\"numeric\" required><button type=\"submit\">Check<\/button>\n  <\/form>\n  <p class=\"feedback\"><\/p>\n<\/div>\n<div class=\"quiz-question\" data-correct=\"a\">\n  <div class=\"question-text\"><p>What does the following cursed Python 2 code print?<\/p><\/div>\n\n  <div>\n<p><img alt=\"A tiny cursed snippet of Python code.\" src=\"\/user\/pages\/02.blog\/python-quiz-europython-2026-edition\/_cursed.webp\"><\/p>\n<\/div>\n\n  <ul class=\"choices\"><li data-option=\"a\"><code>'a'<\/code><\/li>\n    <li data-option=\"b\"><code>25<\/code><\/li>\n    <li data-option=\"c\"><code>True<\/code><\/li>\n    <li data-option=\"d\"><code>SyntaxError<\/code><\/li>\n  <\/ul><p class=\"feedback\"><\/p>\n<\/div>\n<h2 id=\"explanations\">Explanations<a href=\"#explanations\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<h3 id=\"question-1-hosting-europython\">Question 1 &mdash; Hosting EuroPython<a href=\"#question-1-hosting-europython\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><a href=\"https:\/\/ep2009.europython.eu\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">EuroPython 2009<\/a> and <a href=\"https:\/\/ep2010.europython.eu\/about\/venue.html\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">2010<\/a> was hosted in Birmingham.\n<a href=\"https:\/\/ep2015.europython.eu\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">EuroPython 2015<\/a> and <a href=\"https:\/\/ep2016.europython.eu\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">2016<\/a> was hosted in Bilbao.\n<a href=\"https:\/\/ep2023.europython.eu\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">EuroPython 2023<\/a>, <a href=\"https:\/\/ep2024.europython.eu\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">2024<\/a>, and <a href=\"https:\/\/ep2025.europython.eu\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">2025<\/a> was hosted in Prague.\nOf the four options, Lisbon is the only European city that never hosted an EuroPython.<\/p>\n<h3 id=\"question-2-poster-presentations\">Question 2 &mdash; poster presentations<a href=\"#question-2-poster-presentations\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>Originally, 9 poster presentations were scheduled.\nAfter a mixup and a couple cancellations we ended with only 6.<\/p>\n<h3 id=\"question-3-github-stars\">Question 3 &mdash; GitHub stars<a href=\"#question-3-github-stars\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>The official quiz asked you to order all four projects, from most stars to least stars.\nCan you do it?<\/p>\n<p>On the 15th of July of 2026, this would be the correct ordering:<\/p>\n<ol><li>FastAPI, 101k<\/li>\n<li>Django, 88.2k<\/li>\n<li>uv, 87.5k<\/li>\n<li>CPython, 73.8k<\/li>\n<\/ol><h3 id=\"question-4-commits\">Question 4 &mdash; commits<a href=\"#question-4-commits\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>On the 15th of July of 2026, GitHub reported the following number of all-time...<\/p>","summary":"Replay the EuroPython 2026 Python quiz.","date_modified":"2026-07-21T18:13:18+02:00","tags":["conferences","python","quiz"],"image":"\/user\/pages\/02.blog\/python-quiz-europython-2026-edition\/thumbnail.webp"},{"title":"itertools cheatsheet","date_published":"2026-07-13T16:28:00+02:00","id":"https:\/\/mathspp.com\/blog\/itertools-cheatsheet","url":"https:\/\/mathspp.com\/blog\/itertools-cheatsheet","content_html":"<p>Cheatsheet with visual diagrams that explain how the iterables from <code>itertools<\/code> work.<\/p>\n\n<p>This cheatsheet contains diagrams that explain how the iterables from the module <code>itertools<\/code> work in a visual way.<\/p>\n<p><a href=\"https:\/\/gumroad.com\/l\/cheatsheet-itertools\" class=\"btn btn-lg btn-center external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Download this cheatsheet<\/a><\/p>\n<p><img alt=\"A4 itertools cheatsheet shown in light and dark themes.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_cheatsheets-light-front.webp\"><\/p>\n<p><img alt=\"A4 itertools cheatsheet shown in light and dark themes.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_cheatsheets-dark-front.webp\"><\/p>\n<p><a href=\"https:\/\/gumroad.com\/l\/itertools-uv\" class=\"btn btn-lg btn-center external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Download this cheatsheet<\/a><\/p>\n<hr>\n<h2 id=\"reshaping\">Reshaping<a href=\"#reshaping\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<h3 id=\"batched\"><code>batched<\/code><a href=\"#batched\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how batched works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_batched_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how batched works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_batched_light_bg.webp\"><\/p>\n<h3 id=\"islice\"><code>islice<\/code><a href=\"#islice\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how islice works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_islice_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how islice works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_islice_light_bg.webp\"><\/p>\n<h3 id=\"pairwise\"><code>pairwise<\/code><a href=\"#pairwise\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how pairwise works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_pairwise_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how pairwise works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_pairwise_light_bg.webp\"><\/p>\n<h3 id=\"chain\"><code>chain<\/code><a href=\"#chain\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how chain works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_chain_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how chain works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_chain_light_bg.webp\"><\/p>\n<h3 id=\"groupby\"><code>groupby<\/code><a href=\"#groupby\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how groupby works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_groupby_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how groupby works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_groupby_light_bg.webp\"><\/p>\n<h2 id=\"filtering\">Filtering<a href=\"#filtering\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<h3 id=\"filterfalse\"><code>filterfalse<\/code><a href=\"#filterfalse\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how filterfalse works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_filterfalse_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how filterfalse works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_filterfalse_light_bg.webp\"><\/p>\n<h3 id=\"takewhile-dropwhile\">\n<code>takewhile<\/code> &amp; <code>dropwhile<\/code>\n<a href=\"#takewhile-dropwhile\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how takewhile and dropwhile work.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_takewhile_dropwhile_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how takewhile and dropwhile work.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_takewhile_dropwhile_light_bg.webp\"><\/p>\n<h3 id=\"compress\"><code>compress<\/code><a href=\"#compress\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how compress works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_compress_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how compress works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_compress_light_bg.webp\"><\/p>\n<h2 id=\"infinite\">Infinite<a href=\"#infinite\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<h3 id=\"repeat\"><code>repeat<\/code><a href=\"#repeat\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how repeat works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_repeat_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how repeat works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_repeat_light_bg.webp\"><\/p>\n<h3 id=\"cycle\"><code>cycle<\/code><a href=\"#cycle\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how cycle works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_cycle_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how cycle works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_cycle_light_bg.webp\"><\/p>\n<h3 id=\"count\"><code>count<\/code><a href=\"#count\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how count works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_count_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how count works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_count_light_bg.webp\"><\/p>\n<h2 id=\"complementary\">Complementary<a href=\"#complementary\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<h3 id=\"zip-longest\"><code>zip_longest<\/code><a href=\"#zip-longest\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how zip_longest works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_zip_longest_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how zip_longest works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_zip_longest_light_bg.webp\"><\/p>\n<h3 id=\"starmap\"><code>starmap<\/code><a href=\"#starmap\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how starmap works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_starmap_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how starmap works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_starmap_light_bg.webp\"><\/p>\n<h3 id=\"accumulate\"><code>accumulate<\/code><a href=\"#accumulate\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how accumulate works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_accumulate_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how accumulate works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_accumulate_light_bg.webp\"><\/p>\n<p>By default, <code>accumulate<\/code> uses addition as its operation.\nThe magic in using <code>functools.reduce<\/code> and <code>itertools.accumulate<\/code> well is in realising the function that combines elements can be an arbitrary function of two arguments.\nFor example, you can imagine you're a painter and you're going to mix the colours in your palette:<\/p>\n<p><img alt=\"Visual diagram explaining how accumulate works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_accumulate_mix_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how accumulate works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_accumulate_mix_light_bg.webp\"><\/p>\n<h2 id=\"combinatorial\">Combinatorial<a href=\"#combinatorial\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<h3 id=\"product\"><code>product<\/code><a href=\"#product\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how product works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_product_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how product works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_product_light_bg.webp\"><\/p>\n<p>When you want to compute the product of an iterable with itself two or more times, you can also use the argument <code>repeat<\/code>:<\/p>\n<p><img alt=\"Visual diagram explaining how product works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_product_repeat_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how product works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_product_repeat_light_bg.webp\"><\/p>\n<h3 id=\"permutations\"><code>permutations<\/code><a href=\"#permutations\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how permutations work.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_permutations_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how permutations work.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_permutations_light_bg.webp\"><\/p>\n<h3 id=\"combinations\"><code>combinations<\/code><a href=\"#combinations\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how combinations work.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_combinations_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how combinations work.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_combinations_light_bg.webp\"><\/p>\n<h3 id=\"combinations-with-replacement\"><code>combinations_with_replacement<\/code><a href=\"#combinations-with-replacement\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p><img alt=\"Visual diagram explaining how combinations_with_replacement works.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_combinations_with_replacement_dark_bg.webp\">\n<img alt=\"Visual diagram explaining how combinations_with_replacement works.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_combinations_with_replacement_light_bg.webp\"><\/p>\n<hr>\n<p><a href=\"https:\/\/gumroad.com\/l\/cheatsheet-itertools\" class=\"btn btn-lg btn-center external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Download this cheatsheet<\/a><\/p>\n<p><img alt=\"A4 itertools cheatsheet shown in light and dark themes.\" class=\"dark-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_cheatsheets-light-front.webp\"><\/p>\n<p><img alt=\"A4 itertools cheatsheet shown in light and dark themes.\" class=\"light-theme-only\" src=\"\/user\/pages\/02.blog\/itertools-cheatsheet\/_cheatsheets-dark-front.webp\"><\/p>\n<p><a href=\"https:\/\/gumroad.com\/l\/itertools-uv\" class=\"btn btn-lg btn-center external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Download this cheatsheet<\/a><\/p>","summary":"Cheatsheet with visual diagrams that explain how the iterables from itertools work.","date_modified":"2026-07-22T18:06:55+02:00","tags":["python","programming","itertools","modules"],"image":"\/user\/pages\/02.blog\/itertools-cheatsheet\/thumbnail.webp"},{"title":"Write a coding agent from first principles: better tools","date_published":"2026-07-06T15:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/write-a-coding-agent-from-first-principles-better-tools","url":"https:\/\/mathspp.com\/blog\/write-a-coding-agent-from-first-principles-better-tools","content_html":"<p>Improve the capabilities of your agent by providing it with better tools.<\/p>\n\n<h2 id=\"introduction\">Introduction<a href=\"#introduction\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>This tutorial builds on <a href=\"\/blog\/write-a-coding-agent-from-first-principles\">the coding agent you implemented in the tutorial &ldquo;Write a coding agent from first principles&rdquo;<\/a>.\nIn this tutorial, you'll take your agent and improve its capabilities by implementing the text edit and bash command tools that Anthropic provides.<\/p>\n<h2 id=\"why-use-anthropic-s-tools\">Why use Anthropic's tools?<a href=\"#why-use-anthropic-s-tools\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>In the previous tutorial you implemented a coding agent that has a few tools that it can use to read, write, and execute, code.\nThe tool <code>\"bash\"<\/code> can be used to execute arbitrary commands and the tools <code>\"read\"<\/code>, <code>\"write\"<\/code>, <code>\"replace\"<\/code>, and <code>\"insert\"<\/code>, can be used to edit files.<\/p>\n<p>As it turns out, these tools are so universally useful that Anthropic trained its models on specific schema definitions for these tools.\nThe tools still run on the client side, so you'll still get tool use blocks in the API responses, but you don't have to define the schema for the tool.\nYou just specify the tools by <a href=\"https:\/\/platform.claude.com\/docs\/en\/agents-and-tools\/tool-use\/tool-reference#anthropic-provided-tools\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">their Anthropic types and names<\/a>, and the LLMs will happily request tool uses.<\/p>\n<p>Anthropic trains their models on a number of useful tools but you'll focus your attention on two tools that emulate the functionality you already have:<\/p>\n<ol><li><strong>Text editor tool<\/strong>: this tool replaces the four tools you defined to read, write, replace, and insert, text in text files<\/li>\n<li><strong>Bash tool<\/strong>: this tool provides a persistent bash session that can run bash commands<\/li>\n<\/ol><p>By replacing your tools with Anthropic's, the agent will be able to make better tool calls consistently, since Anthropic trains their models on their specific tool schemas.<\/p>\n<h2 id=\"the-native-text-editor-tool\">The native text editor tool<a href=\"#the-native-text-editor-tool\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>To define support for Anthropic's text editor tool you need to add it to your list of tools.\nThe name of the tool is <code>\"str_replace_based_edit_tool\"<\/code> and its type is <code>\"text_editor_20250728\"<\/code>.\n(The type carries <a href=\"https:\/\/platform.claude.com\/docs\/en\/agents-and-tools\/tool-use\/tool-reference#tool-versioning\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">a versioning suffix<\/a> that may influence the tool's behaviour, so make sure you use the right date suffix.)<\/p>\n<p>Since you'll be using Anthropic's text editor tool, you can delete the functions <code>read<\/code>, <code>write<\/code>, <code>replace<\/code>, and <code>insert<\/code>, and the corresponding dictionaries that go in the list <code>TOOLS<\/code>.\nInstead, add the dictionary that specifies the Anthropic tool:<\/p>\n<pre><code class=\"language-py\"># ...\nTOOLS = [\n    {\n        \"type\": \"text_editor_20250728\",\n        \"name\": \"str_replace_based_edit_tool\",\n    }\n]\n\n# Bash tool defined and added later.<\/code><\/pre>\n<p>For organisation purposes, you'll define the text editor tool and the bash tool in their own submodules, so create the folder <code>tools<\/code> and then create the file <code>tools\/str_replace_based_edit_tool.py<\/code> under <code>src\/agent<\/code>.\nIn there, you'll define the code to handle the tool call.<\/p>\n<p>The <a href=\"https:\/\/platform.claude.com\/docs\/en\/agents-and-tools\/tool-use\/text-editor-tool\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">text editor tool<\/a> is a 4-in-1 tool that allows you to <em>view<\/em>, <em>replace<\/em>, <em>create<\/em>, and <em>insert<\/em>, text.\nTo disambiguate the action you want to do, the tool use request includes a <em>command<\/em>:<\/p>\n<pre><code class=\"language-py\"># Example tool use dictionary:\n{\n  \"type\": \"tool_use\",\n  \"id\": \"toolu_01A09q90qw90lq917835lq9\",\n  \"name\": \"str_replace_based_edit_tool\",\n  \"input\": {\n    \"command\": \"view\",  # &lt;--\n    # ...\n  }\n}<\/code><\/pre>\n<p>You'll use the key <code>\"command\"<\/code> from the...<\/p>","summary":"Improve the capabilities of your agent by providing it with better tools.","date_modified":"2026-07-07T09:58:48+02:00","tags":["llms","programming","python"],"image":"\/user\/pages\/02.blog\/write-a-coding-agent-from-first-principles-better-tools\/thumbnail.webp"},{"title":"Write a coding agent from first principles","date_published":"2026-06-22T14:32:00+02:00","id":"https:\/\/mathspp.com\/blog\/write-a-coding-agent-from-first-principles","url":"https:\/\/mathspp.com\/blog\/write-a-coding-agent-from-first-principles","content_html":"<p>Learn how to write a coding agent in this Python tutorial that teaches how to interact with an LLM through an API, how to manage the conversation context, and how to do tool calling.<\/p>\n\n<h2 id=\"introduction\">Introduction<a href=\"#introduction\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>This tutorial will show you how to create your own <strong>coding agent<\/strong> from first principles.\nBy doing so, you'll understand how coding agents work under the hood.<\/p>\n<h2 id=\"prerequisites\">Prerequisites<a href=\"#prerequisites\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>To be able to follow this tutorial, you'll need<\/p>\n<ul><li>\n<strong>prior Python experience<\/strong>: this tutorial is not suitable for people who don't have programming experience<\/li>\n<li>\n<strong>a valid Claude API key<\/strong>: you can get a Claude API key in <a href=\"https:\/\/platform.claude.com\/dashboard\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">the Claude Console dashboard<\/a> [^1]<\/li>\n<li>\n<strong>uv<\/strong>: to manage the project you'll be working on<\/li>\n<\/ul><p>The <em>concepts<\/em> explained in this tutorial are independent from your LLM provider <em>but<\/em> the code snippets will make use of the Claude API and its Python SDK.\nThis means that you can follow along with a different model provider as long as you adapt the code snippets to match the format expected by the API of your provider.<\/p>\n<h2 id=\"what-s-a-coding-agent\">What's a coding agent?<a href=\"#what-s-a-coding-agent\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>A <strong>coding agent<\/strong> is an agent that's specialised for coding.\nIn turn, an agent is just an LLM that has been extended with extra functionality that allows it to interact with its environment.\nThis <em>extra functionality<\/em> is provided through <strong>tools<\/strong>, one of the core ideas covered in this tutorial.<\/p>\n<p>This short definition still hides a lot of details, but instead of giving you a theoretical definition you can <em>learn<\/em> what a coding agent is by creating one.\nThat starts now.<\/p>\n<h2 id=\"project-set-up\">Project set up<a href=\"#project-set-up\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>To set your project up, start by using uv to create a packageable app project:[^2]<\/p>\n<pre><code class=\"language-bash\">% uv init --app --package agent\nInitialized project `agent` at `\/Users\/rodrigogs\/Documents\/mathspp\/agent`<\/code><\/pre>\n<p>Then, <code>cd<\/code> into the project and add the two dependencies you'll need:<\/p>\n<pre><code class=\"language-py\">% cd agent\n% uv add python-dotenv anthropic<\/code><\/pre>\n<p>You'll use <code>python-dotenv<\/code> to help you with authentication to access the Claude API and you'll use the dependency <code>anthropic<\/code> to make it easier to interact with the Claude API.<\/p>\n<p>To set up authentication, create a <code>.env<\/code> file and paste your Claude API key there in front of the variable <code>ANTHROPIC_API_KEY<\/code>.\nWhen you're done, your <code>.env<\/code> file should look like this:<\/p>\n<pre><code class=\"language-text\">ANTHROPIC_API_KEY=\"sk-ant-api03-qI_3mJ...\"<\/code><\/pre>\n<p>To make sure you <em>never<\/em> upload your API key to GitHub by accident, add the file <code>.env<\/code> to your <code>.gitignore<\/code>:<\/p>\n<pre><code class=\"language-text\"># .gitignore\n# ... other entries generated by uv\n.env<\/code><\/pre>\n<p>Now that you've set up your project, you can make your first request to the Claude API.<\/p>\n<h2 id=\"interacting-with-an-llm\">Interacting with an LLM<a href=\"#interacting-with-an-llm\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>A <strong>coding agent<\/strong> needs an LLM at its core.\nYour LLM can come from any provider you want but you're going to use Claude because its SDK (the dependency <code>anthropic<\/code> you added in the previous section) is easy to use and because Claude is a popular model provider.<\/p>\n<p>Using the <code>anthropic<\/code> SDK, here's how you can send a message to the LLM:<\/p>\n<pre><code class=\"language-py\"># src\/agent\/__init__.py\nfrom anthropic import Anthropic\nimport dotenv\n\ndotenv.load_dotenv()  # Load .env\n\nMODEL = \"claude-haiku-4-5\"...<\/code><\/pre>","summary":"Learn how to write a coding agent in this Python tutorial that teaches how to interact with an LLM through an API, how to manage the conversation context, and how to do tool calling.","date_modified":"2026-07-07T09:58:48+02:00","tags":["python","programming","llms"],"image":"\/user\/pages\/02.blog\/write-a-coding-agent-from-first-principles\/thumbnail.webp"},{"title":"TIL #145 \u2013 collections.deque is implemented in blocks","date_published":"2026-05-20T09:25:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/collections-deque-is-implemented-in-blocks","url":"https:\/\/mathspp.com\/blog\/til\/collections-deque-is-implemented-in-blocks","content_html":"<p>Today I learned that <code>collections.deque<\/code> is implemented as a doubly-linked list of blocks.<\/p>\n\n<h2 id=\"collections-deque\"><code>collections.deque<\/code><a href=\"#collections-deque\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>I've written about the data structure <code>deque<\/code> from the module <code>collections<\/code> extensively.\nIn particular, I wrote a <a href=\"\/blog\/python-deque-tutorial\"><code>deque<\/code> tutorial with plenty of practical example use cases of <code>deque<\/code><\/a>.<\/p>\n<p>Today, after some discussion during a cohort I was teaching, a student <a href=\"https:\/\/github.com\/python\/cpython\/blob\/d948eaa366029bc358dbe9cf32d545c3ad30c502\/Modules\/_collectionsmodule.c#L82-L127\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">sent a link to the <code>collections.deque<\/code> source code<\/a> where a comment explains some of the lower-level details of how a <code>deque<\/code> is implemented.<\/p>\n<h2 id=\"double-ended-queue\">Double-ended queue<a href=\"#double-ended-queue\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The name &ldquo;deque&rdquo; stands for Double-Ended QUEue and that's because a deque is a doubly-linked list.\nWhen you learn about that, you might think that, under the hood, a <code>deque<\/code> is essentially a collection of nodes that link to the next and to the previous:<\/p>\n<pre><code class=\"language-py\">class Node:\n    prev_node: Node | None\n    value: object\n    next_node: Node | None\n\nclass deque:\n    first_node: Node | None\n    last_node: Node | None\n    ...<\/code><\/pre>\n<p>But that's not the case.\nApparently, a <code>deque<\/code> is implemented in a more optimised way, where each &ldquo;node&rdquo; is actually a block that can hold up to a certain number of elements.\nAt the level of C, this means you need to manipulate memory less often, which makes the <code>deque<\/code> faster.<\/p>\n<h2 id=\"pseudo-implementation-of-deque-in-python\">Pseudo-implementation of <code>deque<\/code> in Python<a href=\"#pseudo-implementation-of-deque-in-python\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The Python code below is a pseudo-implementation of <code>deque<\/code> that mimics more or less the underlying block mechanism that's in place for Python 3.15 (and that <em>has been in place for decades<\/em>).\nThe Python code below is stripped of all of the memory operations and other lower-level details and instead focuses on the mechanics of managing blocks:<\/p>\n<pre><code class=\"language-py\">from dataclasses import dataclass, field\n\nBLOCKLEN = 64\nCENTRE = (BLOCKLEN - 1) \/\/ 2\n\ndef new_empty_block_data() -&gt; list[object]:\n    return [None for _ in range(BLOCKLEN)]\n\n@dataclass\nclass Block:\n    left_link: Block | None = None\n    data: list[object] = field(default_factory=new_empty_block_data)\n    right_link: Block | None = None\n\n@dataclass(init=False)\nclass deque:\n    left_block: Block\n    right_block: Block\n    left_index: int\n    right_index: int\n    maxlen: int\n\n    def __init__(self, maxlen: int | None = None) -&gt; None:\n        self.left_block = self.right_block = Block()\n        self.left_index = CENTRE + 1\n        self.right_index = CENTRE\n        if maxlen is None:\n            maxlen = -1\n        self.maxlen = maxlen<\/code><\/pre>\n<p>The two classes <code>Block<\/code> and <code>deque<\/code> set the structure for the <code>deque<\/code>.\nThe attributes <code>left_block<\/code> and <code>right_block<\/code> point, respectively, to the leftmost block and the rightmost block, and the first item of a deque <code>d<\/code> is always found at <code>d.left_block[d.left_index]<\/code> while the last item is at <code>d.right_block[d.right_index]<\/code>.<\/p>\n<p>With this in mind, adding or removing elements from a deque is a matter of managing the blocks and the indices correctly.\nBelow, you can find the pseudo-implementation of <code>append<\/code> and <code>pop<\/code>:<\/p>\n<pre><code class=\"language-py\">@dataclass\nclass deque:\n    ...\n\n    def append(self, item: object) -&gt; None:\n        # If there's no space, create a new block.\n        if self.right_index == BLOCKLEN - 1:\n            new_block = Block()\n            self.right_block.right_link = new_block\n            new_block.left_link = self.right_block\n            self.right_block = new_block\n            self.right_index = -1\n\n        self.right_index += 1\n        self.right_block[self.right_index] = item\n\n        if self.maxlen &gt; -1 and len(self) &gt; self.maxlen:\n            self.popleft()\n\n    def pop(self) -&gt; object:\n        item = self.right_block[self.right_index]\n        self.right_index -= 1\n\n        #...<\/code><\/pre>","summary":"Today I learned that collections.deque is implemented as a doubly-linked list of blocks.","date_modified":"2026-05-20T10:54:10+02:00","image":"\/user\/pages\/02.blog\/04.til\/145.collections-deque-is-implemented-in-blocks\/thumbnail.webp"},{"title":"TIL #144 \u2013 Sentinel built-in","date_published":"2026-05-01T19:49:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/sentinel-builtin","url":"https:\/\/mathspp.com\/blog\/til\/sentinel-builtin","content_html":"<p>Today I learned Python 3.15 will get a new sentinel built-in.<\/p>\n\n<p>Sentinel values are unique placeholder values that are commonly used in programming.\nPython 3.15 ships with a new built-in <code>sentinel<\/code> that can be used to create new sentinel values:<\/p>\n<pre><code class=\"language-py\"># Python 3.15+\n&gt;&gt;&gt; MISSING = sentinel(\"MISSING\")\n&gt;&gt;&gt; MISSING\nMISSING<\/code><\/pre>\n<p>Before this built-in was added, the most common sentinel idiom used the built-in <code>object<\/code>:<\/p>\n<pre><code class=\"language-py\">MISSING = object()\n\ndef my_function(some_arg=MISSING):\n    if some_arg is MISSING:\n        ... # Handle the sentinel<\/code><\/pre>\n<p>In the function above, the sentinel value <code>MISSING<\/code> is being used to check whether the user passed <em>anything<\/em> as the parameter <code>some_arg<\/code> or not.\n<a href=\"https:\/\/peps.python.org\/pep-0661\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">PEP 661<\/a>, that introduced this built-in, has a great discussion covering the reasons as to why this pattern, and many other sentinel patterns, fall short.\nIn general, each common sentinel idiom suffers from at least one of the following problems:<\/p>\n<ol>\n<li><strong>Bad string repr<\/strong>: the <a href=\"\/blog\/pydonts\/str-and-repr\">string representation<\/a> is too long and uninformative<\/li>\n<li><strong>Type unsafe<\/strong>: the sentinels don't have a distinct type so it becomes hard or impossible to write code that uses the sentinels and is type safe<\/li>\n<li><strong>Unexpected copy behaviour<\/strong>: the sentinels can't be copied or pickled without breaking the sentinel behaviour<\/li>\n<\/ol>","summary":"Today I learned Python 3.15 will get a new sentinel built-in.","date_modified":"2026-05-01T21:18:58+02:00","tags":["programming","python"],"image":"\/user\/pages\/02.blog\/04.til\/144.sentinel-builtin\/thumbnail.webp"},{"title":"TIL #143 \u2013 Resolve a lazy import manually","date_published":"2026-04-27T17:18:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/resolve-a-lazy-import-manually","url":"https:\/\/mathspp.com\/blog\/til\/resolve-a-lazy-import-manually","content_html":"<p>Learn how to work around the Python machinery to resolve an explicit lazy import manually.<\/p>\n\n<p>A couple of articles ago I wrote about how you could <a href=\"\/blog\/til\/inspect-a-lazy-import\">inspect a lazy import<\/a>.<\/p>\n<p>Apparently, you can use a similar trick to check the attributes and methods that a lazy import has:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; lazy import json\n&gt;&gt;&gt; dir(globals()[\"json\"])\n['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'resolve']<\/code><\/pre>\n<p>Apart from a large number of <a href=\"\/blog\/pydonts\/dunder-methods\">dunder methods<\/a> and dunder attributes, you'll find the method <code>resolve<\/code>.\nYou can run <code>help(globals()[\"json\"].resolve)<\/code> to get the help text on that method:<\/p>\n<pre><code class=\"language-text\">Help on built-in function resolve:\n\nresolve() method of builtins.lazy_import instance\n    resolves the lazy import and returns the actual object<\/code><\/pre>\n<p>This shows that it's the method <code>resolve<\/code> that resolves a lazy import.<\/p>\n<p>If you call the method, you can get access to the resolved module:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; lazy import json\n&gt;&gt;&gt; resolved_json = globals()[\"json\"].resolve()\n&gt;&gt;&gt; resolved_json\n&lt;module 'json' from '\/Users\/rodrigogs\/.local\/share\/uv\/python\/cpython-3.15.0a8-macos-aarch64-none\/lib\/python3.15\/json\/__init__.py'&gt;<\/code><\/pre>\n<p>After calling <code>resolve<\/code>, the lazy module doesn't disappear automatically:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; globals()[\"json\"]\n&lt;lazy_import 'json'&gt;<\/code><\/pre>\n<p>Which shows that the mechanism that's responsible for reification <em>most likely<\/em> calls the method <code>resolve<\/code> and then <em>reassigns<\/em> the name of the module to the module returned by <code>resolve<\/code>.\nIn a way, it's as if the reification process ran something like<\/p>\n<pre><code class=\"language-py\">globals()[\"json\"] = globals()[\"json\"].resolve()<\/code><\/pre>\n<p>In hindsight, this isn't too surprising.\nAfter all, Python tends to be very consistent.\nThe only mistery that remains is <em>what<\/em> triggers the reification process.\nHow is it that Python can detect when something <em>touches<\/em> the lazy import..?<\/p>","summary":"Learn how to work around the Python machinery to resolve an explicit lazy import manually.","date_modified":"2026-04-27T18:29:12+02:00","tags":["programming","python"],"image":"\/user\/pages\/02.blog\/04.til\/143.resolve-a-lazy-import-manually\/thumbnail.webp"},{"title":"Personal highlights of PyCon Lithuania 2026","date_published":"2026-04-11T14:23:00+02:00","id":"https:\/\/mathspp.com\/blog\/personal-highlights-of-pycon-lithuania-2026","url":"https:\/\/mathspp.com\/blog\/personal-highlights-of-pycon-lithuania-2026","content_html":"<p>In this article I share my personal highlights of PyCon Lithuania 2026.<\/p>\n\n<h2 id=\"shout-out-to-the-organisers-and-volunteers\">Shout out to the organisers and volunteers<a href=\"#shout-out-to-the-organisers-and-volunteers\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>This was my second time at PyCon Lithuania and, for the second time in a row, I leave with the impression that everything was very well organised and smooth.\nMaybe the organisers and volunteers were stressed out all the time &mdash; organising a conference is never easy &mdash; but everything looked under control all the time and well thought-through.<\/p>\n<p>Thank you for an amazing experience!<\/p>\n<p>And by the way, congratulations for 15 years of PyCon Lithuania.\nTo celebrate, they even served a gigantic cake during the first networking event.\nThe cake was <em>at least<\/em> 80cm by 30cm:<\/p>\n<figure class=\"image-caption\"><img title=\"The PyCon Lithuania cake.\" alt=\"A picture of a large rectangular cake with the PyCon Lithuania logo in the middle.\" src=\"\/user\/pages\/02.blog\/personal-highlights-of-pycon-lithuania-2026\/_cake.webp\"><figcaption class=\"\">The PyCon Lithuania cake.<\/figcaption><\/figure><p>I'll be honest with you: I didn't expect the cake to be good.\nThe quality of food tends to degrade when it's cooked at a large scale...\nBut even the taste was great and the cake had three coloured layers in yellow, green, and red.<\/p>\n<h2 id=\"social-activities\">Social activities<a href=\"#social-activities\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The organisers prepared <em>two<\/em> networking events, a speakers' dinner, and three city tours (one per evening) for speakers.\nThere was <em>always<\/em> something for you to do.<\/p>\n<p>The city tour is a brilliant idea and I wonder why more conferences don't do it:<\/p>\n<ul><li>Participants get to know a bit more of the city that's hosting the conference.<\/li>\n<li>Participants get the chance to talk to each other in a relaxed and informal environment.<\/li>\n<li>Hiring a tour guide is typically fairly cheap, especially when compared to organising a full-blown social event in a dedicated venue and with dedicated catering.<\/li>\n<\/ul><p>I had taken the city tour last time I had been at PyCon Lithuania and taking it again was not a mistake.\nHere's our group at the end of the tour, immediately before the speakers' dinner:<\/p>\n<figure class=\"image-caption\"><img title=\"Some PyCon Lithuania speakers at the city tour.\" alt=\"Some PyCon Lithuania speakers smile at the camera in front of Gediminas's castle.\" src=\"\/user\/pages\/02.blog\/personal-highlights-of-pycon-lithuania-2026\/_tour.webp\"><figcaption class=\"\">Some PyCon Lithuania speakers at the city tour.<\/figcaption><\/figure><p>The conference organisers even made sure that the city tour ended close to the location of the speakers' dinner <em>and<\/em> that the tour ended at the same time as the dinner started.\nAnother small detail that was carefully planned.<\/p>\n<p>The atmosphere of the restaurant was very pleasant and the staff there was helpful and kind, so we had a wonderful night.\nAt some point, at our table, we noticed that the folks at the other two tables were projecting something on a big screen.\nThere was a large curtain that partially separated our table from the other two, so we took some time to realise that an impromptu Python quiz was about to take place.<\/p>\n<p>I'm (way too) competitive and immediately got up to play.\nAfter six questions, which included learning about the existence of the web framework <em>Falcon<\/em> and correctly reordering the first four sentences of the Zen of Python, I was crowned the winner:<\/p>\n<figure class=\"image-caption\"><img title=\"The final score for the quiz.\" alt=\"A slanted picture of a blue screen showing the player RGS at the top of the quiz podium.\" src=\"\/user\/pages\/02.blog\/personal-highlights-of-pycon-lithuania-2026\/_quiz.webp\"><figcaption class=\"\">The final score for the quiz.<\/figcaption><\/figure><p>The top three players got a <em>free<\/em> spin on the PyCon Lithuania wheel of fortune.<\/p>\n<h2 id=\"egg-hunt-and-swag\">Egg hunt and swag<a href=\"#egg-hunt-and-swag\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>On each day of the conference there was an egg hunt running...<\/p>","summary":"In this article I share my personal highlights of PyCon Lithuania 2026.","date_modified":"2026-04-18T17:13:32+02:00","tags":["python","conferences","opinion"],"image":"\/user\/pages\/02.blog\/personal-highlights-of-pycon-lithuania-2026\/thumbnail.webp"},{"title":"Who wants to be a millionaire: iterables edition","date_published":"2026-04-09T23:17:00+02:00","id":"https:\/\/mathspp.com\/blog\/who-wants-to-be-a-millionaire-iterables-edition","url":"https:\/\/mathspp.com\/blog\/who-wants-to-be-a-millionaire-iterables-edition","content_html":"<p>Play this short quiz to test your Python knowledge!<\/p>\n\n<script src=\"\/user\/themes\/myquark\/js\/quiz.js\"><\/script>\n<link rel=\"stylesheet\" href=\"\/user\/themes\/myquark\/css\/quiz-custom.css\">\n<p>At PyCon Lithuania 2026 I did a lightning talk where I presented a \u201cWho wants to be a millionaire?\u201d Python quiz, themed around iterables.\nThere's a whole performance during the lightning talk which was recorded and will be eventually linked to from here.\nThis article includes only the four questions, the options presented, and a basic system that allows you to check whether you got it right or not.<\/p>\n<h2 id=\"question-1\">Question 1<a href=\"#question-1\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>This is an easy one to get you started.\nIt makes more sense if you watch the <em>performance<\/em> of the lightning talk.<\/p>\n<div class=\"quiz-question\" data-correct=\"a\">\n  <div class=\"question-text\"><p>What is the output of the following Python program?<\/p><\/div>\n  <pre><code class=\"language-py hljs language-python\">print(\"Hello, world!\")<\/code><\/pre>\n  <ul class=\"choices\"><li data-option=\"a\">Hello, world!<\/li>\n    <li data-option=\"b\">Hello world!<\/li>\n    <li data-option=\"c\">Hello world<\/li>\n    <li data-option=\"d\">Hello world!!<\/li>\n  <\/ul><p class=\"feedback\"><\/p>\n<\/div>\n<h2 id=\"question-2\">Question 2<a href=\"#question-2\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<div class=\"quiz-question\" data-correct=\"a\">\n  <div class=\"question-text\"><p>What is the output of the following Python program?<\/p><\/div>\n  <pre><code class=\"language-py hljs language-python\">squares = (x ** 2 for x in range(3))\nprint(type(squares))<\/code><\/pre>\n  <ul class=\"choices\"><li data-option=\"a\"><code>&lt;class 'generator'&gt;<\/code><\/li>\n    <li data-option=\"b\"><code>&lt;class 'gen_expr'&gt;<\/code><\/li>\n    <li data-option=\"c\"><code>&lt;class 'list'&gt;<\/code><\/li>\n    <li data-option=\"d\"><code>&lt;class 'tuple'&gt;<\/code><\/li>\n  <\/ul><p class=\"feedback\"><\/p>\n<\/div>\n<h2 id=\"question-3\">Question 3<a href=\"#question-3\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>This was a reference to the talk I'd given earlier today, where I talked about <code>tee<\/code>.\nThe only object in <code>itertools<\/code> that is not an iterable.<\/p>\n<div class=\"quiz-question\" data-correct=\"a\">\n  <div class=\"question-text\"><p>Out of the 20, how many objects in <code>itertools<\/code> are iterables?<\/p><\/div>\n  <ul class=\"choices\"><li data-option=\"a\">19<\/li>\n    <li data-option=\"b\">20<\/li>\n    <li data-option=\"c\">1<\/li>\n    <li data-option=\"d\">0<\/li>\n  <\/ul><p class=\"feedback\"><\/p>\n<\/div>\n<h2 id=\"question-4\">Question 4<a href=\"#question-4\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<div class=\"quiz-question\" data-correct=\"d\">\n  <div class=\"question-text\"><p>What is the output of the following Python program?<\/p><\/div>\n  <pre><code class=\"language-py hljs language-python\">from itertools import *\n\nprint(sum(chain.from_iterable(chain(*next(\nislice(permutations(islice(batched(pairwise(\ncount()),5),3,9)),15,None)))))<\/code><\/pre>\n  <ul class=\"choices\"><li data-option=\"a\">1800<\/li>\n    <li data-option=\"b\">0<\/li>\n    <li data-option=\"c\">\ud83c\uddf1\ud83c\uddf9\u2764\ufe0f\ud83d\udc0d<\/li>\n    <li data-option=\"d\"><code>SyntaxError<\/code><\/li>\n  <\/ul><p class=\"feedback\"><\/p>\n<\/div>","summary":"Play this short quiz to test your Python knowledge!","date_modified":"2026-04-09T22:29:23+02:00","tags":["python","quiz"],"image":"\/user\/pages\/02.blog\/who-wants-to-be-a-millionaire-iterables-edition\/thumbnail.webp"},{"title":"uv skills for coding agents","date_published":"2026-04-09T14:19:00+02:00","id":"https:\/\/mathspp.com\/blog\/uv-skills","url":"https:\/\/mathspp.com\/blog\/uv-skills","content_html":"<p>This article shares two skills you can add to your coding agents so they use uv workflows.<\/p>\n\n<p>I have fully adopted uv into my workflows and most of the time I want my coding agents to use uv workflows as well, like when running any Python code or managing and running scripts that may or may not have dependencies.<\/p>\n<p>To make this more convenient for me, I created two <code>SKILL.md<\/code> files for two of the most common workflows that the coding agents get wrong on the first few tries:<\/p>\n<ol><li><code>python-via-uv<\/code>: this skill tells the agent that it should use uv whenever it wants to run any piece of Python code, be it one-liners or scripts. This is relevant because I don't even have the command <code>python<\/code>\/<code>python3<\/code> in the shell path, so whenever the LLM tries running something with <code>python ...<\/code>, it fails.<\/li>\n<li><code>uv-script-workflow<\/code>: this skill is specifically for when the agent wants to create and run a script. It instructs the LLM to initalise the script with <code>uv init --script ...<\/code> and then tells it about the relevant commands to manage the script dependencies.<\/li>\n<\/ol><p>The two skills also add a note about sandboxing, since uv's default cache directory will be outside your sandbox.\nWhen that's the case, the agent is already instructed to use a valid temporary location for the uv cache.<\/p>\n<p><em>Installing<\/em> a skill usually just means dropping a Markdown file in the correct folder, but you should check the documentation for the tools you use.<\/p>\n<p>Here are the two skills for you to download:<\/p>\n<ol><li><a href=\"\/blog\/uv-skills\/.\/SKILL-python-via-uv.txt\">Skill for <code>python-via-uv<\/code><\/a><\/li>\n<li><a href=\"\/blog\/uv-skills\/.\/SKILL-uv-script-workflow.txt\">Skill for <code>uv-script-workflow<\/code><\/a><\/li>\n<\/ol><p>I also included the skills verbatim here, for your convenience:<\/p>\n<details><summary>Skill for <code>python-via-uv<\/code><\/summary><pre><code class=\"language-markdown\">---\nname: python-via-uv\ndescription: Enforce Python execution through `uv` instead of direct interpreter calls. Use when Codex needs to run Python scripts, modules, one-liners, tools, test runners, or package commands in a workspace and should avoid invoking `python` or `python3` directly.\n---\n\n# Python Via Uv\n\nUse `uv` for every Python command.\n\nDo not run `python`.\nDo not run `python3`.\nDo not suggest `python` or `python3` in instructions unless the user explicitly requires them and the constraint must be called out as a conflict.\n\n## Execution Rules\n\nWhen sandboxed, set `UV_CACHE_DIR` to a temporary directory the agent can write to before running `uv` commands.\n\nPrefer these patterns:\n\n- Run a script: `UV_CACHE_DIR=\/tmp\/uv-cache uv run path\/to\/script.py`\n- Run a module: `UV_CACHE_DIR=\/tmp\/uv-cache uv run -m package.module`\n- Run a one-liner: `UV_CACHE_DIR=\/tmp\/uv-cache uv run python -c \"print('hello')\"`\n- Run a tool exposed by dependencies: `UV_CACHE_DIR=\/tmp\/uv-cache uv run tool-name`\n- Add a dependency for an ad hoc command: `UV_CACHE_DIR=\/tmp\/uv-cache uv run --with &lt;package&gt; python -c \"...\"`\n\n## Notes\n\nUsing `python` inside `uv run ...` is acceptable because `uv` is still the entrypoint controlling interpreter selection and environment setup.\n\nIf the workspace already defines a project-specific temporary cache directory, prefer that over `\/tmp\/uv-cache`.\n\nIf a command example or existing documentation uses `python` or `python3` directly, translate it to the closest `uv` form before executing it....<\/code><\/pre><\/details>","summary":"This article shares two skills you can add to your coding agents so they use uv workflows.","date_modified":"2026-04-18T17:13:32+02:00","tags":["python","programming","LLM","uv"],"image":"\/user\/pages\/02.blog\/uv-skills\/thumbnail.webp"}]}
