<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mouse Vs Python</title>
	<atom:link href="https://blog.pythonlibrary.org/feed/" rel="self" type="application/rss+xml" />
	<link>https://papayawhip-oyster-325761.hostingersite.com/</link>
	<description>Where You Can Learn All About Python Programming</description>
	<lastBuildDate>Fri, 17 Apr 2026 12:57:02 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://blog.pythonlibrary.org/wp-content/uploads/2019/05/cropped-narnyish_highres-32x32.png</url>
	<title>Mouse Vs Python</title>
	<link>https://papayawhip-oyster-325761.hostingersite.com/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Textual &#8211; An Intro to DOM Queries (Part I)</title>
		<link>https://blog.pythonlibrary.org/2026/04/17/textual-an-intro-to-dom-queries-part-i/</link>
		
		<dc:creator><![CDATA[Mike]]></dc:creator>
		<pubDate>Fri, 17 Apr 2026 12:57:02 +0000</pubDate>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Textual]]></category>
		<category><![CDATA[TJUI]]></category>
		<guid isPermaLink="false">https://blog.pythonlibrary.org/?p=12778</guid>

					<description><![CDATA[<p>In this article, you will learn how to query the DOM in Textual. You will discover that the DOM keeps track of all the widgets in your application. By running queries against the DOM, you can find widgets quickly and update them, too. You will be learning the following topics related to the DOM: The [&#8230;]</p>
<p>The post <a href="https://blog.pythonlibrary.org/2026/04/17/textual-an-intro-to-dom-queries-part-i/">Textual &#8211; An Intro to DOM Queries (Part I)</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this article, you will learn how to query the DOM in Textual. You will discover that the DOM keeps track of all the widgets in your application. By running queries against the DOM, you can find widgets quickly and update them, too.</p>
<p>You will be learning the following topics related to the DOM:</p>
<ul>
<li>The query one method</li>
<li>Textual queries</li>
</ul>
<p>You will learn more in the second part of this series next week!</p>
<p>You will soon see the value of working with DOM queries and the power that these queries give you. Let&#8217;s get started!</p>
<h2>The Query One Method</h2>
<p>You will find the query_one() method throughout the Textual documentation and many Textual applications on GitHub. You may use query_one() to retrieve a single widget that matches a CSS selector or a widget type.</p>
<p>You can pass in up to two parameters to query_one():</p>
<ul>
<li>The CSS selector</li>
<li>The widget type</li>
<li>Or both at the same time</li>
</ul>
<p>If you pass both, pass the CSS selector first, with the widget type as the second parameter.</p>
<p>Try some of this out. Open up your Python editor and create a file named query_input.py. Then enter this code in it:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python"># query_input.py

from textual.app import App, ComposeResult
from textual.widgets import Button, Input


class QueryInput(App):

    def compose(self) -&gt; ComposeResult:
        yield Input()
        yield Button("Update Input")

    def on_button_pressed(self) -&gt; None:
        input_widget = self.query_one(Input)
        new_string = f"You entered: {input_widget.value}"
        input_widget.value = new_string


if __name__ == "__main__":
    app = QueryInput()
    app.run()</pre>
<p>Your code creates an <code>Input</code> and a <code>Button</code> widget. Enter some text in the <code>Input</code> widget and press the button. Your <code>on_button_pressed()</code> method will get called. You call <code>query_one()</code> and pass it an <code>Input</code> widget. Then, you update the returned <code>Input</code> widget’s value with a new string.</p>
<p>Here is what the application might look like:</p>
<p><img fetchpriority="high" decoding="async" class="aligncenter size-large wp-image-12779" src="https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_input-1024x551.png" alt="" width="1024" height="551" srcset="https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_input-1024x551.png 1024w, https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_input-300x161.png 300w, https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_input-768x413.png 768w, https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_input-1536x827.png 1536w, https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_input.png 2018w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<p>Now, you will try writing a new piece of code where you use <code>query_one()</code> with a CSS selector. Create a new file called <code>query_one_same_ids.py</code> and use this code:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python"># query_one_same_ids.py

from textual.app import App, ComposeResult
from textual.widgets import Button, Label


class QueryApp(App):

    def compose(self) -&gt; ComposeResult:
        yield Label("Press a button", id="label")
        yield Button("Test", id="button")

    def on_button_pressed(self) -&gt; None:
        widget = self.query_one("#label")
        widget.update("You pressed the button!")


if __name__ == "__main__":
    app = QueryApp()
    app.run()</pre>
<p>In this example, you create two widgets with different IDs. Then you use <code>query_one()</code> to select the <code>Label</code> widget and update its text.</p>
<p>If you call <code>query_one()</code> and there are no matches, you will get a <code>NoMatches</code> exception. On the other hand, if there is more than one match, the method will return the first item that does match.</p>
<p>What will the following code do if you put it in your example above?</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">self.query_one(”#label”, Button)</pre>
<p>If you guessed that Textual will raise an exception, you should congratulate yourself. You have good intuition! If the widget matches the CSS selector but not the widget type, then you will get a <code>WrongType</code> exception raised.</p>
<h2 class="header-anchor-post"><strong>Textual Queries</strong></h2>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA">
<div id="§textual-queries" class="pencraft pc-reset header-anchor offset-top"></div>
</div>
</div>
<p>Textual has more than one way to query the DOM. You may also use the <code>query()</code> method, which you can use to query or find multiple widgets. When you call <code>query()</code>, it will return a DOMQuery object, which behaves as a list-like container of widgets.</p>
<p>You can see how this works by writing some code. Create a new Python file named <code>query_all.py</code> and add this code to it:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python"># query_all.py

from textual.app import App, ComposeResult
from textual.widgets import Button, Label


class QueryApp(App):

    def compose(self) -&gt; ComposeResult:
        yield Label("Press a button", id="label")
        yield Button("Test", id="button")

    def on_button_pressed(self) -&gt; None:
        widgets = self.query()
        s = ""
        for widget in widgets:
            s += f"{widget}\n"
        label = self.query_one("#label")
        label.update(s)


if __name__ == "__main__":
    app = QueryApp()
    app.run()</pre>
<p dir="auto">The idea is to get all the widgets in your application and print them out. Of course, you can&#8217;t print out anything when your terminal application is blocking stdout, so instead, you create a string of widgets separated by new lines and update the <code>Label</code> widget.</p>
<p dir="auto">Here is an example of what you might get if you run the code and press the button on your machine:</p>
<p dir="auto"><img decoding="async" class="aligncenter size-large wp-image-12780" src="https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_all-1024x551.png" alt="" width="1024" height="551" srcset="https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_all-1024x551.png 1024w, https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_all-300x161.png 300w, https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_all-768x413.png 768w, https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_all-1536x827.png 1536w, https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_all.png 2018w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<p dir="auto">You might be surprised by that output. Perhaps you thought you would only see a <code>Label</code> and a <code>Button</code> widget in that list? If so, you forgot that a <code>Screen</code> widget is always lurking in the background. But there are also two more: a <code>ToastRack</code> and a <code>Tooltip</code> widget. These come with all your applications. The <code>ToastRack</code> positions <code>Toast</code> widgets, which you use to display a notification message. A <code>Tooltip</code> is a message that appears when you hover your mouse over a widget.</p>
<p dir="auto">You do not need to know more about those extra widgets now.</p>
<p dir="auto">Also note that all query methods can be used on both the <code>App</code> and <code>Widget</code> subclasses, which is very handy.</p>
<div class="markdown-heading" dir="auto">
<h3 class="heading-element" dir="auto" tabindex="-1">Using Selectors</h3>
<p><a id="user-content-using-selectors" class="anchor" href="https://github.com/driscollis/creating_tuis/blob/main/manuscript/05_query.md#using-selectors" aria-label="Permalink: Using Selectors"></a></div>
<p dir="auto">You can use CSS selectors with <code>query()</code> in much the same way as you can with <code>query_one()</code>. The difference, of course, is that <code>query()</code> always returns an iterable DOMObject.</p>
<p dir="auto">Let&#8217;s pretend you want to get all the <code>Button</code> widgets in your application and iterate over them. Create a new Python script called <code>query_button.py</code> with this code:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python"># query_buttons.py

from textual.app import App, ComposeResult
from textual.widgets import Button, Label


class QueryApp(App):

    def compose(self) -&gt; ComposeResult:
        yield Label("Press a button", id="label")
        yield Button("One", id="one")
        yield Button("Two", id="two")
        yield Button("Three")

    def on_button_pressed(self) -&gt; None:
        s = ""
        for widget in self.query("Button"):
            s += f"{widget}\n"
        label = self.query_one("#label")
        label.update(s)


if __name__ == "__main__":
    app = QueryApp()
    app.run()</pre>
<p>Here you are passing in a string, &#8220;Button&#8221;, to <code>query()</code>. If using <code>query_one</code>, you would use the <code>Button</code> type directly. Regardless, when you run this code and press the button, you will see the following:</p>
<p><img decoding="async" class="aligncenter size-large wp-image-12781" src="https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_buttons-1024x551.png" alt="" width="1024" height="551" srcset="https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_buttons-1024x551.png 1024w, https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_buttons-300x161.png 300w, https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_buttons-768x413.png 768w, https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_buttons-1536x827.png 1536w, https://blog.pythonlibrary.org/wp-content/uploads/2026/04/query_buttons.png 2018w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<p dir="auto">That worked great! This time, you queried the DOM and returned all the <code>Button</code> widgets in your application.</p>
<p dir="auto">What if you wanted to find all the disabled buttons in your code? You can disable widgets using the <code>disabled</code> style flag or the CSS attribute. To find those widgets, you would update the query like this: <code>widgets = self.query("Button.disabled")</code>.</p>
<div class="markdown-heading" dir="auto">
<h3 class="heading-element" dir="auto" tabindex="-1">Results</h3>
<p><a id="user-content-results" class="anchor" href="https://github.com/driscollis/creating_tuis/blob/main/manuscript/05_query.md#results" aria-label="Permalink: Results"></a></div>
<p dir="auto">The query objects in Textual also provide a <code>results()</code> method that you can use as an alternative way of iterating over the widgets. For example, you can use <code>results()</code> to rewrite the query above that would retrieve all the disabled buttons to be something like this:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">widgets = self.query(".disabled").results(Button)
s = ""
for widget in widgets:
    s += f"{widget}\n"</pre>
<p dir="auto">This code combines the last example query with the last full code example. Although this latter version is more verbose, you might find it easier to read than the original query for disabled widgets.</p>
<p dir="auto">Another benefit of using <code>results()</code> is that Python type checkers, such as Mypy, can use it to determine the widget type in the loop. When you do not use <code>results()</code>, then Mypy will only know that you are looping over a <code>Widget</code> object, rather than a <code>Button</code> object.</p>
<h2 class="header-anchor-post">Wrapping Up</h2>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA">
<div id="§wrapping-up" class="pencraft pc-reset header-anchor offset-top"></div>
</div>
</div>
<p>You learned the basics of using Textual’s DOM query methods in this article. You can use these query methods to access one or more widgets in your user interface.</p>
<p>Specifically, you learned about the following:</p>
<ul>
<li>The query one method</li>
<li>Textual queries</li>
</ul>
<p>Textual is a great way to create a user interface with Python. You should check it out today!</p>
<h2 class="header-anchor-post">Learn More</h2>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA"><span style="font-size: 16px;">Want to learn more about Textual? Check out my book, <strong>Creating TUI Applications with Textual and Python</strong>:</span></div>
<div>
<ul>
<li class="header-anchor-post"><a href="https://driscollis.gumroad.com/l/textual">Gumroad</a></li>
<li class="header-anchor-post"><a href="https://leanpub.com/textual/">Leanpub</a></li>
<li class="header-anchor-post"><a href="https://www.amazon.com/dp/B0FGDNC3H6">Amazon</a></li>
</ul>
</div>
</div>
<p>The post <a href="https://blog.pythonlibrary.org/2026/04/17/textual-an-intro-to-dom-queries-part-i/">Textual &#8211; An Intro to DOM Queries (Part I)</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Python Pop Quiz &#8211; Number Explosion</title>
		<link>https://blog.pythonlibrary.org/2026/04/02/python-pop-quiz-number-explosion/</link>
		
		<dc:creator><![CDATA[Mike]]></dc:creator>
		<pubDate>Thu, 02 Apr 2026 12:29:39 +0000</pubDate>
				<category><![CDATA[beginner]]></category>
		<category><![CDATA[Books]]></category>
		<category><![CDATA[Education]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[quiz]]></category>
		<guid isPermaLink="false">https://blog.pythonlibrary.org/?p=12775</guid>

					<description><![CDATA[<p>You will sometimes come across examples of code that use one or two asterisks. Depending on how the asterisks are used, they can mean different things to Python. Check your understanding of what a single asterisk means in the following quiz! The Quiz What will be the output if you run this code? numbers = [&#8230;]</p>
<p>The post <a href="https://blog.pythonlibrary.org/2026/04/02/python-pop-quiz-number-explosion/">Python Pop Quiz &#8211; Number Explosion</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p dir="auto">You will sometimes come across examples of code that use one or two asterisks. Depending on how the asterisks are used, they can mean different things to Python.</p>
<p dir="auto">Check your understanding of what a single asterisk means in the following quiz!</p>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">The Quiz</h2>
<p><a id="user-content-the-quiz" class="anchor" href="https://github.com/driscollis/pyquiz_book/blob/main/02_number_explosion.md#the-quiz" aria-label="Permalink: The Quiz"></a></div>
<p dir="auto">What will be the output if you run this code?</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">numbers = range(3)
output = {*numbers}
print(output)</pre>
<p dir="auto">A) <code>{range}</code></p>
<p dir="auto">B) <code>(range)</code></p>
<p dir="auto">C) <code>[0, 1, 2]</code></p>
<p dir="auto">D) <code>(0, 1, 2)</code></p>
<p dir="auto">E) <code>{0, 1, 2}</code></p>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">Hint</h2>
<p><a id="user-content-hint" class="anchor" href="https://github.com/driscollis/pyquiz_book/blob/main/02_number_explosion.md#hint" aria-label="Permalink: Hint"></a></div>
<p dir="auto">&#8220;Unpacking generalizations&#8221; is the term to look up if you get stuck..</p>
<p dir="auto"><img loading="lazy" decoding="async" class="aligncenter size-large wp-image-11679" src="https://blog.pythonlibrary.org/wp-content/uploads/2022/10/quiz_kick-1024x698.jpg" alt="The Python Quiz Book" width="1024" height="698" srcset="https://blog.pythonlibrary.org/wp-content/uploads/2022/10/quiz_kick-1024x698.jpg 1024w, https://blog.pythonlibrary.org/wp-content/uploads/2022/10/quiz_kick-300x204.jpg 300w, https://blog.pythonlibrary.org/wp-content/uploads/2022/10/quiz_kick-768x523.jpg 768w, https://blog.pythonlibrary.org/wp-content/uploads/2022/10/quiz_kick-1536x1046.jpg 1536w, https://blog.pythonlibrary.org/wp-content/uploads/2022/10/quiz_kick-2048x1395.jpg 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">The Answer</h2>
<p><a id="user-content-the-answer" class="anchor" href="https://github.com/driscollis/pyquiz_book/blob/main/02_number_explosion_answer.md#the-answer" aria-label="Permalink: The Answer"></a></div>
<p dir="auto"><strong>E) <code>{0, 1, 2}</code></strong></p>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">Explanation</h2>
<p><a id="user-content-explanation" class="anchor" href="https://github.com/driscollis/pyquiz_book/blob/main/02_number_explosion_answer.md#explanation" aria-label="Permalink: Explanation"></a></div>
<p dir="auto">A single asterisk before a Python dictionary or list is known as the unpacking operator. In this example, you tell Python to unpack three integers (0 &#8211; 2) into a set.</p>
<p dir="auto">Here is the example running in a REPL:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">&gt;&gt;&gt; numbers = range(3)
&gt;&gt;&gt; output = {*numbers}
&gt;&gt;&gt; print(output)
{0, 1, 2}
&gt;&gt;&gt; print(type(output))
&lt;class 'set'&gt;</pre>
<p dir="auto">The code output shows that you have created a set!</p>
<p dir="auto">You can also use a single asterisk to unpack a dictionary&#8217;s keys:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">&gt;&gt;&gt; my_dict = {1: "one", 2: "two", 3: "three"}
&gt;&gt;&gt; print({*my_dict})
{1, 2, 3}</pre>
<p>If you want to take your knowledge of unpacking further, it can help to see Python functions use asterisks:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">&gt;&gt;&gt; def my_func(*args):
...     print(args)
... 
&gt;&gt;&gt; my_func(1)
(1,)
&gt;&gt;&gt; numbers = range(3)
&gt;&gt;&gt; output = {*numbers}
&gt;&gt;&gt; my_func(output)
({0, 1, 2},)
&gt;&gt;&gt; my_func(*output)
(0, 1, 2)</pre>
<p dir="auto">When you see a single asterisk in a function definition, the asterisk means that the function can take an unlimited number of arguments. In the second example, you pass in the set as a single argument, while in the last example, you use a single asterisk to unpack the numbers and pass them in as three separate arguments.</p>
<p dir="auto">For more information, see <a href="https://peps.python.org/pep-0448/" rel="nofollow">PEP 448 – Additional Unpacking Generalizations</a>, which has many more examples!</p>
<h2 dir="auto">Get the Book</h2>
<p>Want to try out over one HUNDRED more quizzes? Check out the book!</p>
<p><strong>Purchase at <a href="https://driscollis.gumroad.com/l/pyquiz">Gumroad</a> or <a href="https://leanpub.com/pyquiz">Leanpub</a> or <a href="https://www.amazon.com/dp/B0BVT8DZV1">Amazon</a></strong></p>
<p>The post <a href="https://blog.pythonlibrary.org/2026/04/02/python-pop-quiz-number-explosion/">Python Pop Quiz &#8211; Number Explosion</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Vibe Coding Pong with Python and pygame</title>
		<link>https://blog.pythonlibrary.org/2026/03/30/vibe-coding-pong-with-python-and-pygame/</link>
		
		<dc:creator><![CDATA[Mike]]></dc:creator>
		<pubDate>Mon, 30 Mar 2026 12:29:01 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Game]]></category>
		<category><![CDATA[pygame]]></category>
		<guid isPermaLink="false">https://blog.pythonlibrary.org/?p=12768</guid>

					<description><![CDATA[<p>Pong is one of the first computer games ever created, way back in 1972. If you have never heard of Pong, you can think of it as a kind of &#8220;tennis&#8221; game. There are two paddles, on each side of the screen. They move up and down. The goal is to bounce a ball between [&#8230;]</p>
<p>The post <a href="https://blog.pythonlibrary.org/2026/03/30/vibe-coding-pong-with-python-and-pygame/">Vibe Coding Pong with Python and pygame</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p dir="auto">Pong is one of the first computer games ever created, way back in 1972. If you have never heard of Pong, you can think of it as a kind of &#8220;tennis&#8221; game. There are two paddles, on each side of the screen. They move up and down. The goal is to bounce a ball between the two paddles. If you miss the ball, your opponent scores a point.</p>
<p dir="auto">Atari created Pong and put it in arcades. The name of the game is derived from the game of ping-pong. Pong has been remade many times, with different features and gameplay elements added or removed.</p>
<h3 class="header-anchor-post"><a href="https://driscollis.gumroad.com/l/vibegames" rel="">Want to know more? Get the Book!</a></h3>
<p dir="auto">You will use Anthropic&#8217;s Claude AI to create this game in Python using the pygame package.</p>
<p dir="auto">Let&#8217;s get started!</p>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">Creating the Game</h2>
</div>
<blockquote>
<p dir="auto"><strong>Prompt</strong>: Please create the pong videogame using Python and pygame. Give the user a way to start a new game and keep score.</p>
</blockquote>
<p dir="auto">I&#8217;ll create a classic Pong game for you using Python and pygame. This will include two paddles, a ball, scoring, and the ability to start new games.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">import pygame
import sys
import random

# Initialize Pygame
pygame.init()

# Constants
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
PADDLE_WIDTH = 15
PADDLE_HEIGHT = 90
BALL_SIZE = 15
PADDLE_SPEED = 7
BALL_SPEED_X = 6
BALL_SPEED_Y = 6

# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (128, 128, 128)

class Paddle:
    def __init__(self, x, y):
        self.rect = pygame.Rect(
            x, y, PADDLE_WIDTH, PADDLE_HEIGHT)
        self.speed = PADDLE_SPEED
    
    def move_up(self):
        if self.rect.top &gt; 0:
            self.rect.y -= self.speed
    
    def move_down(self):
        if self.rect.bottom &lt; SCREEN_HEIGHT:
            self.rect.y += self.speed
    
    def draw(self, screen):
        pygame.draw.rect(screen, WHITE, self.rect)

class Ball:
    def __init__(self):
        self.rect = pygame.Rect(
            SCREEN_WIDTH // 2, 
            SCREEN_HEIGHT // 2, 
            BALL_SIZE,
            BALL_SIZE)
        self.reset_ball()
    
    def reset_ball(self):
        self.rect.center = (SCREEN_WIDTH // 2, 
            SCREEN_HEIGHT // 2)
        self.speed_x = BALL_SPEED_X * random.choice([-1, 1])
        self.speed_y = BALL_SPEED_Y * random.choice([-1, 1])
    
    def move(self):
        self.rect.x += self.speed_x
        self.rect.y += self.speed_y
        
        # Bounce off top and bottom walls
        if (self.rect.top &lt;= 0 
            or self.rect.bottom &gt;= SCREEN_HEIGHT):
            self.speed_y = -self.speed_y
    
    def draw(self, screen):
        pygame.draw.rect(screen, WHITE, self.rect)

class PongGame:
    def __init__(self):
        self.screen = pygame.display.set_mode(
            (SCREEN_WIDTH, SCREEN_HEIGHT))
        pygame.display.set_caption("Pong Game")
        self.clock = pygame.time.Clock()
        
        # Create game objects
        self.left_paddle = Paddle(
            30, SCREEN_HEIGHT // 2 - PADDLE_HEIGHT // 2)
        self.right_paddle = Paddle(
            SCREEN_WIDTH - 30 - PADDLE_WIDTH,
            SCREEN_HEIGHT // 2 - PADDLE_HEIGHT // 2)
        self.ball = Ball()
        
        # Scores
        self.left_score = 0
        self.right_score = 0
        self.font = pygame.font.Font(None, 74)
        self.small_font = pygame.font.Font(None, 36)
        
        # Game state
        self.game_state = "menu"  # "menu", "playing", "paused"
    
    def handle_collision(self):
        # Ball collision with paddles
        if self.ball.rect.colliderect(self.left_paddle.rect):
            # Only bounce if moving toward paddle
            if self.ball.speed_x &lt; 0:  
                self.ball.speed_x = -self.ball.speed_x
                # Add some variation based on where ball hits paddle
                hit_pos = (self.ball.rect.centery - self.left_paddle.rect.centery
                          ) / (PADDLE_HEIGHT / 2)
                self.ball.speed_y += hit_pos * 2
        
        if self.ball.rect.colliderect(self.right_paddle.rect):
            # Only bounce if moving toward paddle
            if self.ball.speed_x &gt; 0:  
                self.ball.speed_x = -self.ball.speed_x
                # Add some variation based on where ball hits paddle
                hit_pos = (self.ball.rect.centery - self.right_paddle.rect.centery
                          ) / (PADDLE_HEIGHT / 2)
                self.ball.speed_y += hit_pos * 2
        
        # Limit ball speed
        max_speed = 12
        if abs(self.ball.speed_y) &gt; max_speed:
            self.ball.speed_y = max_speed if self.ball.speed_y &gt; 0 else -max_speed
    
    def check_scoring(self):
        # Check if ball went off screen
        if self.ball.rect.left &lt;= 0:
            self.right_score += 1
            self.ball.reset_ball()
        elif self.ball.rect.right &gt;= SCREEN_WIDTH:
            self.left_score += 1
            self.ball.reset_ball()
    
    def handle_input(self):
        keys = pygame.key.get_pressed()
        
        if self.game_state == "playing":
            # Left paddle controls (W/S)
            if keys[pygame.K_w]:
                self.left_paddle.move_up()
            if keys[pygame.K_s]:
                self.left_paddle.move_down()
            
            # Right paddle controls (UP/DOWN arrows)
            if keys[pygame.K_UP]:
                self.right_paddle.move_up()
            if keys[pygame.K_DOWN]:
                self.right_paddle.move_down()
    
    def draw_menu(self):
        self.screen.fill(BLACK)
        
        title_text = self.font.render("PONG", True, WHITE)
        title_rect = title_text.get_rect(
            center=(SCREEN_WIDTH // 2, 150))
        self.screen.blit(title_text, title_rect)
        
        start_text = self.small_font.render(
            "Press SPACE to Start", True, WHITE)
        start_rect = start_text.get_rect(
            center=(SCREEN_WIDTH // 2, 250))
        self.screen.blit(start_text, start_rect)
        
        controls_text = [
            "Controls:",
            "Left Player: W (Up) / S (Down)",
            "Right Player: Arrow Keys",
            "Press R to restart during game",
            "Press ESC to return to menu"
        ]
        
        for i, text in enumerate(controls_text):
            rendered_text = self.small_font.render(
                text, True, GRAY if i == 0 else WHITE)
            text_rect = rendered_text.get_rect(
                center=(SCREEN_WIDTH // 2, 320 + i * 40))
            self.screen.blit(rendered_text, text_rect)
    
    def draw_game(self):
        self.screen.fill(BLACK)
        
        # Draw center line
        for i in range(0, SCREEN_HEIGHT, 20):
            if i % 40 == 0:
                pygame.draw.rect(
                    self.screen, 
                    WHITE, 
                    (SCREEN_WIDTH // 2 - 2, i, 4, 10))
        
        # Draw paddles and ball
        self.left_paddle.draw(self.screen)
        self.right_paddle.draw(self.screen)
        self.ball.draw(self.screen)
        
        # Draw scores
        left_score_text = self.font.render(
            str(self.left_score), True, WHITE)
        right_score_text = self.font.render(
            str(self.right_score), True, WHITE)
        
        self.screen.blit(left_score_text, (SCREEN_WIDTH // 4, 50))
        self.screen.blit(
            right_score_text, 
            (3 * SCREEN_WIDTH // 4 - right_score_text.get_width(),
             50))
        
        # Draw instructions
        instruction_text = self.small_font.render(
            "Press ESC for menu, R to restart", True, GRAY)
        instruction_rect = instruction_text.get_rect(
            center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT - 30))
        self.screen.blit(instruction_text, instruction_rect)
    
    def reset_game(self):
        self.left_score = 0
        self.right_score = 0
        self.ball.reset_ball()
        self.left_paddle.rect.y = (SCREEN_HEIGHT // 2 - 
            PADDLE_HEIGHT // 2)
        self.right_paddle.rect.y = (SCREEN_HEIGHT // 2 - 
            PADDLE_HEIGHT // 2)
    
    def run(self):
        running = True
        
        while running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                
                if event.type == pygame.KEYDOWN:
                    if (event.key == pygame.K_SPACE 
                        and self.game_state == "menu"):
                        self.game_state = "playing"
                        self.reset_game()
                    elif event.key == pygame.K_ESCAPE:
                        self.game_state = "menu"
                    elif (event.key == pygame.K_r 
                        and self.game_state == "playing"):
                        self.reset_game()
            
            if self.game_state == "menu":
                self.draw_menu()
            elif self.game_state == "playing":
                self.handle_input()
                self.ball.move()
                self.handle_collision()
                self.check_scoring()
                self.draw_game()
            
            pygame.display.flip()
            self.clock.tick(60)
        
        pygame.quit()
        sys.exit()

if __name__ == "__main__":
    game = PongGame()
    game.run()</pre>
<p dir="auto">I&#8217;ve created a complete Pong game in Python using pygame! Here are the key features:</p>
<p dir="auto"><strong>Game Features:</strong></p>
<ul dir="auto">
<li>Classic Pong gameplay with two paddles and a bouncing ball</li>
<li>Score tracking for both players</li>
<li>Menu system with game start option</li>
<li>Ability to restart games and return to menu</li>
</ul>
<p dir="auto"><strong>Controls:</strong></p>
<ul dir="auto">
<li>Left Player: W (up) / S (down)</li>
<li>Right Player: Arrow keys (up/down)</li>
<li>SPACE: Start new game from menu</li>
<li>R: Restart current game</li>
<li>ESC: Return to main menu</li>
</ul>
<p dir="auto"><strong>Game Mechanics:</strong></p>
<ul dir="auto">
<li>Ball bounces off top/bottom walls and paddles</li>
<li>Ball speed varies slightly based on where it hits the paddle</li>
<li>Scores increase when ball goes off either side</li>
<li>Ball resets to center after each score</li>
</ul>
<p dir="auto"><strong>To run the game:</strong></p>
<ul dir="auto">
<li>Make sure you have pygame installed: <code>pip install pygame</code></li>
<li>Save the code to a <code>.py</code> file (e.g., <code>pong.py</code>)</li>
<li>Run it with: <code>python pong.py</code></li>
</ul>
<p dir="auto">The game includes a clean menu system, smooth 60 FPS gameplay, and responsive controls. The ball physics include some randomization to keep gameplay interesting, and the paddle collisions add a bit of strategy by allowing players to influence the ball&#8217;s trajectory based on where they hit it.</p>
<blockquote>
<p dir="auto"><strong>Prompt</strong>: Can you explain how the code works?</p>
</blockquote>
<p dir="auto">I&#8217;ll break down how the Pong game code works, explaining each major component and how they work together.</p>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">Code Structure Overview</h2>
<p>&nbsp;</p>
</div>
<p dir="auto">The code is organized using object-oriented programming with three main classes:</p>
<ul dir="auto">
<li><code>Paddle</code> &#8211; represents the player paddles</li>
<li><code>Ball</code> &#8211; handles the bouncing ball</li>
<li><code>PongGame</code> &#8211; manages the overall game logic and flow</li>
</ul>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element focus-visible" dir="auto" tabindex="-1" data-focus-visible-added="">1. Initialization and Constants</h2>
<pre class="EnlighterJSRAW" data-enlighter-language="python">pygame.init()
# Constants define game dimensions and speeds
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
PADDLE_SPEED = 7</pre>
<p dir="auto">The game starts by initializing pygame and defining constants for screen size, object dimensions, and movement speeds. Using constants makes the code easier to modify and maintain.</p>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">2. The Paddle Class</h2>
<pre class="EnlighterJSRAW" data-enlighter-language="python">class Paddle:
    def __init__(self, x, y):
        self.rect = pygame.Rect(x, y, PADDLE_WIDTH, PADDLE_HEIGHT)</pre>
<p dir="auto">Each paddle is represented as a <code>pygame.Rect</code> object, which provides built-in collision detection and positioning. The paddle has methods to:</p>
<ul dir="auto">
<li><code>move_up()</code> and <code>move_down()</code> &#8211; handle movement with boundary checking</li>
<li><code>draw()</code> &#8211; renders the paddle as a white rectangle</li>
</ul>
<p dir="auto">The boundary checking ensures paddles can&#8217;t move off-screen:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">if self.rect.top &gt; 0:  # Don't go above screen
if self.rect.bottom &lt; SCREEN_HEIGHT:  # Don't go below screen</pre>
<h2 class="heading-element" dir="auto" tabindex="-1">3. The Ball Class</h2>
<pre class="EnlighterJSRAW" data-enlighter-language="python">class Ball:
    def reset_ball(self):
        self.speed_x = BALL_SPEED_X * random.choice([-1, 1])
        self.speed_y = BALL_SPEED_Y * random.choice([-1, 1])</pre>
<p dir="auto">The ball maintains its position and velocity. Key features:</p>
<ul dir="auto">
<li><code>reset_ball()</code> &#8211; centers the ball and gives it a random direction</li>
<li><code>move()</code> &#8211; updates position and handles wall bouncing</li>
<li>Wall collision detection flips the Y velocity: <code>self.speed_y = -self.speed_y</code></li>
</ul>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">4. Main Game Class Structure</h2>
<p>&nbsp;</p>
</div>
<p dir="auto">The PongGame class manages everything:</p>
<p dir="auto"><strong>Game States</strong></p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">self.game_state = "menu"  # "menu", "playing", "paused"</pre>
<p dir="auto">The game uses states to control what&#8217;s displayed and what input is accepted.</p>
<p dir="auto"><strong>Game Loop</strong></p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">def run(self):
    while running:
        # Handle events (keyboard, quit)
        # Update game logic based on current state
        # Draw everything
        # Control frame rate (60 FPS)</pre>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">5. Collision Detection</h2>
<p>&nbsp;</p>
</div>
<p dir="auto">The most complex part handles ball-paddle collisions:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">def handle_collision(self):
    if self.ball.rect.colliderect(self.left_paddle.rect):
        # Only bounce if moving toward paddle
        if self.ball.speed_x &lt; 0:  
            self.ball.speed_x = -self.ball.speed_x</pre>
<p dir="auto"><strong>Key points:</strong></p>
<ul dir="auto">
<li>Uses pygame&#8217;s built-in <code>colliderect()</code> for collision detection</li>
<li>Checks ball direction to prevent multiple bounces</li>
<li>Adds spin based on where the ball hits the paddle:</li>
</ul>
<pre class="EnlighterJSRAW" data-enlighter-language="python">hit_pos = (self.ball.rect.centery - 
           self.left_paddle.rect.centery
           ) / (PADDLE_HEIGHT / 2)
self.ball.speed_y += hit_pos * 2</pre>
<h2 class="heading-element focus-visible" dir="auto" tabindex="-1" data-focus-visible-added="">6. Input Handling</h2>
<pre class="EnlighterJSRAW" data-enlighter-language="python">def handle_input(self):
    keys = pygame.key.get_pressed()
    if keys[pygame.K_w]:
        self.left_paddle.move_up()</pre>
<p dir="auto">The game checks which keys are currently pressed each frame, allowing for smooth continuous movement. Different keys are handled based on the game state.</p>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">7. Scoring System</h2>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">def check_scoring(self):
    if self.ball.rect.left &lt;= 0:  # Ball went off left side
        self.right_score += 1
        self.ball.reset_ball()</pre>
<p dir="auto">Scoring is checked every frame by seeing if the ball has moved past the screen edges.</p>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">8. Rendering System</h2>
</div>
<p dir="auto">The game uses different drawing functions for different states:</p>
<ul dir="auto">
<li><code>draw_menu()</code> &#8211; shows title and instructions</li>
<li><code>draw_game()</code> &#8211; renders paddles, ball, scores, and game elements</li>
</ul>
<p dir="auto">The center dashed line is drawn using a loop:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">for i in range(0, SCREEN_HEIGHT, 20):
    if i % 40 == 0:  # Only draw every other dash
        pygame.draw.rect(
            self.screen, 
            WHITE, 
            (SCREEN_WIDTH // 2 - 2, i, 4, 10))</pre>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">9. Game Flow</h2>
</div>
<ol dir="auto">
<li><strong>Initialization</strong>: Create paddles, ball, set up pygame</li>
<li><strong>Main Loop:</strong></li>
</ol>
<ul dir="auto">
<li>Process input events</li>
<li>Update game logic (if playing)</li>
<li>Draw current state</li>
<li>Maintain 60 FPS with clock.tick(60)</li>
</ul>
<ol dir="auto" start="3">
<li>State Management: Switch between menu and gameplay based on user input</li>
</ol>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">Key Programming Concepts Used</h2>
</div>
<ul dir="auto">
<li><strong>Object-Oriented Design</strong>: Separate classes for different game elements</li>
<li><strong>Event-Driven Programming</strong>: Responding to keyboard and quit events</li>
<li><strong>Game Loop Pattern</strong>: Continuous update-draw cycle</li>
<li><strong>State Management</strong>: Different behaviors based on current game state</li>
<li><strong>Collision Detection</strong>: Using pygame&#8217;s rectangle collision methods</li>
<li><strong>Vector Math</strong>: Ball movement with X/Y velocity components</li>
</ul>
<p dir="auto">The code is structured to be easily extensible &#8211; you could add features like AI opponents, power-ups, or different game modes by building on this foundation.</p>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">Running Pong</h2>
</div>
<p dir="auto">Now that you have the code and understand how to use it, you are ready to run the code. You can run your code in your Python IDE or on the command line like this:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">python pong.py</pre>
<p>When you first launch your game, you will see the following welcome screen:</p>
</div>
<p><img loading="lazy" decoding="async" class="aligncenter size-large wp-image-12769" src="https://blog.pythonlibrary.org/wp-content/uploads/2026/03/pong_main-1024x805.png" alt="Pong main screen" width="1024" height="805" srcset="https://blog.pythonlibrary.org/wp-content/uploads/2026/03/pong_main-1024x805.png 1024w, https://blog.pythonlibrary.org/wp-content/uploads/2026/03/pong_main-300x236.png 300w, https://blog.pythonlibrary.org/wp-content/uploads/2026/03/pong_main-768x604.png 768w, https://blog.pythonlibrary.org/wp-content/uploads/2026/03/pong_main-1536x1207.png 1536w, https://blog.pythonlibrary.org/wp-content/uploads/2026/03/pong_main.png 1608w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p>If you press the SPACE key, you will see the actual game, which will look something like this:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-large wp-image-12772" src="https://blog.pythonlibrary.org/wp-content/uploads/2026/03/pong-1024x805.png" alt="Pong game play" width="1024" height="805" srcset="https://blog.pythonlibrary.org/wp-content/uploads/2026/03/pong-1024x805.png 1024w, https://blog.pythonlibrary.org/wp-content/uploads/2026/03/pong-300x236.png 300w, https://blog.pythonlibrary.org/wp-content/uploads/2026/03/pong-768x604.png 768w, https://blog.pythonlibrary.org/wp-content/uploads/2026/03/pong-1536x1207.png 1536w, https://blog.pythonlibrary.org/wp-content/uploads/2026/03/pong.png 1608w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p dir="auto">Grab a friend or play against yourself. The game works pretty well, although playing solo can be rather challenging.</p>
<div class="markdown-heading" dir="auto">
<h2 class="heading-element" dir="auto" tabindex="-1">Wrapping Up</h2>
<p><a id="user-content-wrapping-up" class="anchor" href="https://github.com/driscollis/creating_games_ai_book/blob/main/manuscript/02_pong.md#wrapping-up" aria-label="Permalink: Wrapping Up"></a></div>
<p dir="auto">Pong is a fun little game. Much like ping-pong or table tennis, the game is designed to be played with someone else. Technically, you could also create a computer opponent, but you usually play Pong between two people instead.</p>
<p dir="auto">You should play the game with a friend or family member. You can also study the code to discover how it works. Then, when you are ready, you can start improving the game.</p>
<h2 class="header-anchor-post">Get the Book</h2>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA">
<div id="§get-the-book" class="pencraft pc-reset header-anchor offset-top"></div>
</div>
</div>
<p>This article is from my latest Python book, Vibe Coding Video Games with Python.</p>
<p>You can get <strong>Vibe Coding Video Games with Python</strong> at the following websites:</p>
<ul>
<li><a href="https://leanpub.com/vibegames" rel="">Leanpub</a></li>
<li><a href="https://driscollis.gumroad.com/l/vibegames" rel="">Gumroad</a></li>
<li><a href="https://amzn.to/4byWKaf" rel="">Amazon Kindle</a></li>
</ul>
</div>
</div>
<p>The post <a href="https://blog.pythonlibrary.org/2026/03/30/vibe-coding-pong-with-python-and-pygame/">Vibe Coding Pong with Python and pygame</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>The Python Show &#8211; Python Illustrated</title>
		<link>https://blog.pythonlibrary.org/2026/03/24/the-python-show-python-illustrated/</link>
		
		<dc:creator><![CDATA[Mike]]></dc:creator>
		<pubDate>Tue, 24 Mar 2026 17:59:43 +0000</pubDate>
				<category><![CDATA[beginner]]></category>
		<category><![CDATA[Books]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Podcast]]></category>
		<guid isPermaLink="false">https://blog.pythonlibrary.org/?p=12764</guid>

					<description><![CDATA[<p>In this episode, we hear from two sisters who put together a beginner&#8217;s book about Python. The unique hook for their book is that one sister wrote the text while the other did the illustrations. Listen in as we learn about these incredible sisters and how they got into software programming, writing, and technical education. [&#8230;]</p>
<p>The post <a href="https://blog.pythonlibrary.org/2026/03/24/the-python-show-python-illustrated/">The Python Show &#8211; Python Illustrated</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this episode, we hear from two sisters who put together a beginner&#8217;s book about Python. The unique hook for their book is that one sister wrote the text while the other did the illustrations. Listen in as we learn about these incredible sisters and how they got into software programming, writing, and technical education.</p>
<p><iframe style="width: 100%; max-width: 660px; overflow: hidden; border-radius: 10px;" src="https://embed.podcasts.apple.com/us/podcast/56-python-illustrated/id1691189730?i=1000755016348" height="175" frameborder="0" sandbox="allow-forms allow-popups allow-same-origin allow-scripts allow-storage-access-by-user-activation allow-top-navigation-by-user-activation"></iframe></p>
<p>You can check out their book, Python Illustrated, on <a href="https://www.packtpub.com/en-at/product/python-illustrated-9781836646327" rel="">Packt</a> or <a href="https://amzn.to/4do0JXY" rel="">Amazon</a>.</p>
<p>Maaike is an <a href="https://www.udemy.com/user/maaikevanputtencapgeminicom/" rel="">Udemy instructor</a>, and she also has courses on <a href="https://www.pluralsight.com/authors/maaike-vanputten" rel="">Pluralsight</a>.</p>
<p>This episode was originally published on <a href="https://www.pythonshow.com/">The Python Show</a>!</p>
<p>The post <a href="https://blog.pythonlibrary.org/2026/03/24/the-python-show-python-illustrated/">The Python Show &#8211; Python Illustrated</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Textual &#8211; Creating a Custom Checkbox</title>
		<link>https://blog.pythonlibrary.org/2026/03/16/textual-creating-a-custom-checkbox/</link>
		
		<dc:creator><![CDATA[Mike]]></dc:creator>
		<pubDate>Mon, 16 Mar 2026 19:42:08 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Textual]]></category>
		<category><![CDATA[TUI]]></category>
		<guid isPermaLink="false">https://blog.pythonlibrary.org/?p=12754</guid>

					<description><![CDATA[<p>Textual is a great Python user interface package. Textual lets you create a GUI-like interface in your terminal. You can use many different widgets in Textual. However, the widget you will be focusing on in this tutorial is the humble checkbox. Checkboxes are used for Boolean choices. They return a True if checked and a [&#8230;]</p>
<p>The post <a href="https://blog.pythonlibrary.org/2026/03/16/textual-creating-a-custom-checkbox/">Textual &#8211; Creating a Custom Checkbox</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Textual is a great Python user interface package. Textual lets you create a GUI-like interface in your terminal.</p>
<p>You can use many different widgets in Textual. However, the widget you will be focusing on in this tutorial is the humble checkbox.</p>
<p>Checkboxes are used for Boolean choices. They return a True if checked and a False if unchecked. You can use a checkbox as a clear visual cue to indicate whether one or more options are enabled or disabled.</p>
<p>In this tutorial, you will learn the following:</p>
<ul>
<li>How to create a standard checkbox</li>
<li>How to customize the checkbox widget</li>
</ul>
<p>Let’s get started!</p>
<h2 class="header-anchor-post">How to Create a Standard Checkbox</h2>
<p>You should always start with the default widget to see if it works for you. With that in mind, open up your favorite Python IDE and create a new file with the following code in it:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">from textual.app import App, ComposeResult
from textual.containers import VerticalScroll
from textual.widgets import Checkbox


class CheckboxApp(App[None]):

    def compose(self) -&gt; ComposeResult:
        with VerticalScroll():
            yield Checkbox("Mike")

    def on_checkbox_changed(self, event: Checkbox.Changed) -&gt; None:
        self.notify(f"Checkbox value: {event.value}")


if __name__ == "__main__":
    CheckboxApp().run()</pre>
<p>The example above is based on a code example from the <a href="https://textual.textualize.io/widgets/checkbox/#checkbox" rel="">Textual documentation</a>. You don’t have to use a <strong>VerticalScroll</strong> container here, but it is convenient when adding a series of widgets to the container.</p>
<p>Your main focus should be on the <strong>Checkbox</strong> itself. Here, you simply yield it from <strong>compose()</strong>, and then you catch the <strong>Checkbox.Changed</strong> event. When the event is fired, you display a notification to the user indicating that they have changed the checkbox value.</p>
<p>When you run this code, you will see something like this:</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-12758 size-full" src="https://blog.pythonlibrary.org/wp-content/uploads/2026/03/normal_check_output.png" alt="Textual checkbox" width="854" height="335" srcset="https://blog.pythonlibrary.org/wp-content/uploads/2026/03/normal_check_output.png 854w, https://blog.pythonlibrary.org/wp-content/uploads/2026/03/normal_check_output-300x118.png 300w, https://blog.pythonlibrary.org/wp-content/uploads/2026/03/normal_check_output-768x301.png 768w" sizes="auto, (max-width: 854px) 100vw, 854px" /></p>
<p>However, if you want to make the widget’s borders always visible, then you’ll need to add a border to the widget.</p>
<p>But what if you want the checkbox to be completely empty, too, rather than a greyed-out “X”? That is what you will learn how to do in the next section!</p>
<h2 data-pm-slice="1 1 []">How to Customize the Checkbox Widget</h2>
<p>Having a greyed out “X” isn’t necessarily bad thing if you have set up your Textual application to have a lighter background. But if you are using a default or dark background, then you will have some contrast issues.</p>
<p>Many GUI toolkits will show a checkbox as empty for its False state, though, while Textual defaults to a greyed-out “X.” If you want to change the character that is shown or make it an empty box like other toolkits, then you will need to learn how to customize the widget itself.</p>
<p>Fortunately, making a custom widget in Textual is very straightforward. Create a new Python file in your IDE and enter the following code:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">from textual.app import App, ComposeResult
from textual.containers import VerticalScroll
from textual.widgets import Checkbox

class CustomCheck(Checkbox):
    BUTTON_INNER = " "

    def toggle(self) -&gt; None:
        if self.value:
            CustomCheck.BUTTON_INNER = " "
        else:
            CustomCheck.BUTTON_INNER = "X"
        self.value = not self.value
        return self


class CheckboxApp(App[None]):
    #CSS_PATH = "checkbox.tcss"

    def compose(self) -&gt; ComposeResult:
        check = CustomCheck("Mike")

        with VerticalScroll():
            yield check

    def on_checkbox_changed(self, event: Checkbox.Changed) -&gt; None:
        self.notify(f"Checkbox value: {event.value}")


if __name__ == "__main__":
    CheckboxApp().run()</pre>
<p>When you want to customize a pre-existing widget in Textual, you will almost always subclass it. So here, you subclass the <strong>Checkbox</strong> class to create a new <strong>CustomCheck</strong> class. Next, you override the <strong>BUTTON_INNER </strong>class attribute as well as the <strong>toggle()</strong> method.</p>
<p>If you go looking at the source code, you will find that <strong>BUTTON_INNER </strong>defaults to the “X” so here you are defaulting it to an empty string. Then you update <strong>toggle()</strong> to swap the “X” in when it is checked, and swap it back out when it is unchecked.</p>
<p>The other change is to use the new widget class in your application code.</p>
<p>To increase the widget&#8217;s visibility, you can add a border using Textual CSS. Create a new file called <strong>checkbox.tcss</strong> and add the following code to it:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="css">CustomCheck {
    border: round green;
}</pre>
<p>Make sure you save this file in the same folder as your Python file.</p>
<p>Now, when you run this code, you will see the following:</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-12759 size-full" src="https://blog.pythonlibrary.org/wp-content/uploads/2026/03/custom_check_output2.png" alt="Custom Textual checkbox" width="852" height="320" srcset="https://blog.pythonlibrary.org/wp-content/uploads/2026/03/custom_check_output2.png 852w, https://blog.pythonlibrary.org/wp-content/uploads/2026/03/custom_check_output2-300x113.png 300w, https://blog.pythonlibrary.org/wp-content/uploads/2026/03/custom_check_output2-768x288.png 768w" sizes="auto, (max-width: 852px) 100vw, 852px" /></p>
<p>Good job! You now have a custom checkbox.</p>
<h2>Wrapping Up</h2>
<p>Textual is a great way for you to create beautiful user interfaces in your terminal. In this tutorial, you learned how to create a regular checkbox widget and then learned how to create a custom checkbox.</p>
<p>You can apply this knowledge to customize other widgets in Textual. You will need to study the widget’s code closely to understand how it works so you can modify it successfully. You may have to go through several iterations to get exactly what you want.</p>
<p>Don’t give up! You’ll get there eventually, and then you will be proud of yourself for sticking to it!</p>
<h2 class="header-anchor-post">Learn More</h2>
<p>If you thought this article was interesting you and you want to learn more about Textual, check out the following links:</p>
<ul>
<li>The Textual <a href="https://textual.textualize.io/" rel="">website</a></li>
<li><a href="https://driscollis.gumroad.com/l/textual" rel="">Creating TUI Applications with Textual and Python</a> (book)</li>
</ul>
<p>The post <a href="https://blog.pythonlibrary.org/2026/03/16/textual-creating-a-custom-checkbox/">Textual &#8211; Creating a Custom Checkbox</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Python Typing Book Kickstarter</title>
		<link>https://blog.pythonlibrary.org/2026/02/03/python-typing-book-kickstarter/</link>
		
		<dc:creator><![CDATA[Mike]]></dc:creator>
		<pubDate>Tue, 03 Feb 2026 18:17:00 +0000</pubDate>
				<category><![CDATA[beginner]]></category>
		<category><![CDATA[Books]]></category>
		<category><![CDATA[intermediate]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://blog.pythonlibrary.org/?p=12748</guid>

					<description><![CDATA[<p>Python has had type hinting support since Python 3.5, over TEN years ago! However, Python’s type annotations have changed repeatedly over the years. In Python Typing: Type Checking for Python Programmers, you will learn all you need to know to add type hints to your Python applications effectively. You will also learn how to use Python [&#8230;]</p>
<p>The post <a href="https://blog.pythonlibrary.org/2026/02/03/python-typing-book-kickstarter/">Python Typing Book Kickstarter</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Python has had type hinting support since Python 3.5, over TEN years ago! However, Python’s type annotations have changed repeatedly over the years. In <strong>Python Typing: Type Checking for Python Programmers</strong>, you will learn all you need to know to add type hints to your Python applications effectively.</p>
<p>You will also learn how to use Python type checkers, configure them, and set them up in pre-commit or GitHub Actions. This knowledge will give you the power to check your code and your team’s code automatically before merging, hopefully catching defects before they make it into your products.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-medium wp-image-12749" src="https://blog.pythonlibrary.org/wp-content/uploads/2026/02/python_typing_cover-200x300.webp" alt="Python Typing Book Cover" width="200" height="300" srcset="https://blog.pythonlibrary.org/wp-content/uploads/2026/02/python_typing_cover-200x300.webp 200w, https://blog.pythonlibrary.org/wp-content/uploads/2026/02/python_typing_cover-683x1024.webp 683w, https://blog.pythonlibrary.org/wp-content/uploads/2026/02/python_typing_cover-768x1152.webp 768w, https://blog.pythonlibrary.org/wp-content/uploads/2026/02/python_typing_cover-1024x1536.webp 1024w, https://blog.pythonlibrary.org/wp-content/uploads/2026/02/python_typing_cover-1365x2048.webp 1365w, https://blog.pythonlibrary.org/wp-content/uploads/2026/02/python_typing_cover-scaled.webp 1707w" sizes="auto, (max-width: 200px) 100vw, 200px" /></p>
<p class="button-wrapper" style="text-align: center;" data-attrs="{&quot;url&quot;:&quot;https://www.kickstarter.com/projects/driscollis/python-typing-book&quot;,&quot;text&quot;:&quot;Support the Book!&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.kickstarter.com/projects/driscollis/python-typing-book" rel="">Support the Book!</a></p>
<h3 class="header-anchor-post"><strong>What You’ll Learn</strong></h3>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA">
<div id="§what-youll-learn" class="pencraft pc-reset header-anchor offset-top"></div>
</div>
</div>
<p>You will learn all about Python’s support for type hinting (annotations). Specifically, you will learn about the following topics:</p>
<ul>
<li>Variable annotations</li>
<li>Function annotations</li>
<li>Type aliases</li>
<li>New types</li>
<li>Generics</li>
<li>Hinting callables</li>
<li>Annotating TypedDict</li>
<li>Annotating Decorators and Generators</li>
<li>Using Mypy for type checking</li>
<li>Mypy configuration</li>
<li>Using ty for type checking</li>
<li>ty configuration</li>
<li>and more!</li>
</ul>
<h3 class="header-anchor-post"><strong>Rewards to Choose From</strong></h3>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA">
<div id="§rewards-to-choose-from" class="pencraft pc-reset header-anchor offset-top"></div>
</div>
</div>
<p>There are several different rewards you can get in this Kickstarter:</p>
<ul>
<li>A signed paperback copy of the book (See Stretch Goals)</li>
<li>An eBook copy of the book in PDF and ePub</li>
<li>A t-shirt with the cover art from the book (See Stretch Goals)</li>
<li>Other Python eBooks</li>
</ul>
<p class="button-wrapper" style="text-align: center;" data-attrs="{&quot;url&quot;:&quot;https://www.kickstarter.com/projects/driscollis/python-typing-book&quot;,&quot;text&quot;:&quot;Kickstart the Book&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.kickstarter.com/projects/driscollis/python-typing-book" rel="">Kickstart the Book</a></p>
<p>The post <a href="https://blog.pythonlibrary.org/2026/02/03/python-typing-book-kickstarter/">Python Typing Book Kickstarter</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>New Book: Vibe Coding Video Games with Python</title>
		<link>https://blog.pythonlibrary.org/2026/01/19/new-book-vibe-coding-video-games-with-python/</link>
		
		<dc:creator><![CDATA[Mike]]></dc:creator>
		<pubDate>Mon, 19 Jan 2026 14:25:39 +0000</pubDate>
				<category><![CDATA[beginner]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Vibe Coding]]></category>
		<guid isPermaLink="false">https://blog.pythonlibrary.org/?p=12743</guid>

					<description><![CDATA[<p>My latest book, Vibe Coding Video Games with Python, is now available as an eBook. The paperback will be coming soon, hopefully by mid-February at the latest. The book is around 183 pages in length and is 6&#215;9” in size. In this book, you will learn how to use artificial intelligence to create mini-games. You will attempt [&#8230;]</p>
<p>The post <a href="https://blog.pythonlibrary.org/2026/01/19/new-book-vibe-coding-video-games-with-python/">New Book: Vibe Coding Video Games with Python</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>My latest book, <strong>Vibe Coding Video Games with Python,</strong> is now available as an eBook. The paperback will be coming soon, hopefully by mid-February at the latest. The book is around 183 pages in length and is 6&#215;9” in size.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-medium wp-image-12744" src="https://blog.pythonlibrary.org/wp-content/uploads/2026/01/Vibe_coding_video_games600-188x300.jpg" alt="Vibe Coding Video Games with Python" width="188" height="300" srcset="https://blog.pythonlibrary.org/wp-content/uploads/2026/01/Vibe_coding_video_games600-188x300.jpg 188w, https://blog.pythonlibrary.org/wp-content/uploads/2026/01/Vibe_coding_video_games600.jpg 376w" sizes="auto, (max-width: 188px) 100vw, 188px" /></p>
<p>In this book, you will learn how to use artificial intelligence to create mini-games. You will attempt to recreate the look and feel of various classic video games. The intention is not to violate copyright or anything of the sort, but instead to learn the limitations and the power of AI.</p>
<p>Instead, you will simply be learning about whether or not you can use AI to help you know how to create video games. Can you do it with no previous knowledge, as the AI proponents say? Is it really possible to create something just by writing out questions to the ether?</p>
<p>You will use various large language models (LLMs), such as Google Gemini, Grok, Mistral, and CoPilot, to create these games. You will discover the differences and similarities between these tools. You may be surprised to find that some tools give much more context than others.</p>
<p>AI is certainly not a cure-all and is far from perfect. You will quickly discover AI’s limitations and learn some strategies for solving those kinds of issues.</p>
<h3 class="header-anchor-post"><strong>What You’ll Learn</strong></h3>
<p>You’ll be creating “clones” of some popular games. However, these games will only be the first level and may or may not be fully functional.</p>
<ul>
<li>Chapter 1 – The Snake Game</li>
<li>Chapter 2 – Pong Clone</li>
<li>Chapter 3 – Frogger Clone</li>
<li>Chapter 4 – Space Invaders Clone</li>
<li>Chapter 5 – Minesweeper Clone</li>
<li>Chapter 6 – Luna Lander Clone</li>
<li>Chapter 7 – Asteroids Clone</li>
<li>Chapter 8 – Tic-Tac-Toe</li>
<li>Chapter 9 – Pole Position Clone</li>
<li>Chapter 10 – Connect Four</li>
<li>Chapter 11 – Adding Sprites</li>
</ul>
<h3 class="header-anchor-post">Where to Purchase</h3>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA"><span style="font-size: 16px;">You can get </span><strong style="font-size: 16px;">Vibe Coding Video Games with Python</strong><span style="font-size: 16px;"> at the following websites:</span></div>
</div>
<ul>
<li><a href="https://leanpub.com/vibegames" rel="">Leanpub</a></li>
<li><a href="https://driscollis.gumroad.com/l/vibegames" rel="">Gumroad</a></li>
<li><a href="https://amzn.to/4byWKaf" rel="">Amazon Kindle</a></li>
</ul>
<p>The post <a href="https://blog.pythonlibrary.org/2026/01/19/new-book-vibe-coding-video-games-with-python/">New Book: Vibe Coding Video Games with Python</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Type Hint a Decorator in Python</title>
		<link>https://blog.pythonlibrary.org/2026/01/14/how-to-type-hint-a-decorator-in-python/</link>
		
		<dc:creator><![CDATA[Mike]]></dc:creator>
		<pubDate>Wed, 14 Jan 2026 17:04:47 +0000</pubDate>
				<category><![CDATA[intermediate]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Typing]]></category>
		<guid isPermaLink="false">https://blog.pythonlibrary.org/?p=12734</guid>

					<description><![CDATA[<p>Decorators are a concept that can trip up new Python users. You may find this definition helpful: A decorator is a function that takes in another function and adds new functionality to it without modifying the original function. Functions can be used just like any other data type in Python. A function can be passed [&#8230;]</p>
<p>The post <a href="https://blog.pythonlibrary.org/2026/01/14/how-to-type-hint-a-decorator-in-python/">How to Type Hint a Decorator in Python</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Decorators are a concept that can trip up new Python users. You may find this definition helpful: A decorator is a function that takes in another function and adds new functionality to it without modifying the original function.</p>
<p>Functions can be used just like any other data type in Python. A function can be passed to a function or returned from a function, just like a string or integer.</p>
<p>If you have jumped on the type-hinting bandwagon, you will probably want to add type hints to your decorators. That has been difficult until fairly recently.</p>
<p>Let’s see how to type hint a decorator!</p>
<h2 class="header-anchor-post">Type Hinting a Decorator the Wrong Way</h2>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA">
<p><span style="font-size: 16px;">You might think that you can use a </span><code style="font-size: 16px; font-style: inherit; font-weight: inherit;">TypeVar</code><span style="font-size: 16px;"> to type hint a decorator. You will try that first.</span></p>
</div>
</div>
<p>Here’s an example:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">from functools import wraps
from typing import Any, Callable, TypeVar


Generic_function = TypeVar("Generic_function", bound=Callable[..., Any])

def info(func: Generic_function) -&gt; Generic_function:
    @wraps(func)
    def wrapper(*args: Any, **kwargs: Any) -&gt; Any:
        print('Function name: ' + func.__name__)
        print('Function docstring: ' + str(func.__doc__))
        result = func(*args, **kwargs)
        return result
    return wrapper

@info
def doubler(number: int) -&gt; int:
    """Doubles the number passed to it"""
    return number * 2

print(doubler(4))</pre>
<p>If you run <code>mypy —strict info_decorator.py</code> you will get the following output:</p>
<div class="captioned-image-container">
<figure>
<div class="image2-inset can-restack"><picture><source srcset="https://substackcdn.com/image/fetch/$s_!fHQx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca544bc5-619b-460e-8078-50a6c26b0277_1968x554.png 424w, https://substackcdn.com/image/fetch/$s_!fHQx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca544bc5-619b-460e-8078-50a6c26b0277_1968x554.png 848w, https://substackcdn.com/image/fetch/$s_!fHQx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca544bc5-619b-460e-8078-50a6c26b0277_1968x554.png 1272w, https://substackcdn.com/image/fetch/$s_!fHQx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca544bc5-619b-460e-8078-50a6c26b0277_1968x554.png 1456w" type="image/webp" sizes="100vw" /></picture></div>
<div>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">info_decorator.py:14: error: Incompatible return value type (got "_Wrapped[[VarArg(Any), KwArg(Any)], Any, [VarArg(Any), KwArg(Any)], Any]", expected "Generic_function")  [return-value]
Found 1 error in 1 file (checked 1 source file)</pre>
<p>That’s a confusing error! Feel free to search for an answer.</p>
<p>The answers that you find will probably vary from just ignoring the function (i.e. not type hinting it at all) to using something called a <code>ParamSpec</code>.</p>
<p>Let’s try that next!</p>
<h2 class="header-anchor-post">Using a ParamSpec for Type Hinting</h2>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA"><span style="font-size: 16px;">The </span><strong style="font-size: 16px;">ParamSpec</strong><span style="font-size: 16px;"> is a class in Python’s </span><code style="font-size: 16px; font-style: inherit; font-weight: inherit;">typing</code><span style="font-size: 16px;"><span style="font-size: 16px;"> module. Here’s what the docstring says about ParamSpec:</p>
<p></span></span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">class ParamSpec(object):
  """ Parameter specification variable.
  
  The preferred way to construct a parameter specification is via the
  dedicated syntax for generic functions, classes, and type aliases,
  where the use of '**' creates a parameter specification::
  
      type IntFunc[**P] = Callable[P, int]
  
  For compatibility with Python 3.11 and earlier, ParamSpec objects
  can also be created as follows::
  
      P = ParamSpec('P')
  
  Parameter specification variables exist primarily for the benefit of
  static type checkers.  They are used to forward the parameter types of
  one callable to another callable, a pattern commonly found in
  higher-order functions and decorators.  They are only valid when used
  in ``Concatenate``, or as the first argument to ``Callable``, or as
  parameters for user-defined Generics. See class Generic for more
  information on generic types.
  
  An example for annotating a decorator::
  
      def add_logging[**P, T](f: Callable[P, T]) -&gt; Callable[P, T]:
          '''A type-safe decorator to add logging to a function.'''
          def inner(*args: P.args, **kwargs: P.kwargs) -&gt; T:
              logging.info(f'{f.__name__} was called')
              return f(*args, **kwargs)
          return inner
  
      @add_logging
      def add_two(x: float, y: float) -&gt; float:
          '''Add two numbers together.'''
          return x + y
  
  Parameter specification variables can be introspected. e.g.::
  
      &gt;&gt;&gt; P = ParamSpec("P")
      &gt;&gt;&gt; P.__name__
      'P'
  
  Note that only parameter specification variables defined in the global
  scope can be pickled.
   """</pre>
<p>In short, you use a ParamSpec to construct a parameter specification for a generic function, class, or type alias.</p>
<p>To see what that means in code, you can update the previous decorator to look like this:<span style="font-size: 16px;"> </span></p>
</div>
<div>
<pre class="EnlighterJSRAW" data-enlighter-language="python">from functools import wraps
from typing import Callable, ParamSpec, TypeVar


P = ParamSpec("P")
R = TypeVar("R")

def info(func: Callable[P, R]) -&gt; Callable[P, R]:
    @wraps(func)
    def wrapper(*args: P.args, **kwargs: P.kwargs) -&gt; R:
        print('Function name: ' + func.__name__)
        print('Function docstring: ' + str(func.__doc__))
        return func(*args, **kwargs)
    return wrapper

@info
def doubler(number: int) -&gt; int:
    """Doubles the number passed to it"""
    return number * 2

print(doubler(4))</pre>
<p>Here, you create a ParamSpec and a TypeVar. You tell the decorator that it takes in a Callable with a generic set of parameters (P), and you use TypeVar (R) to specify a generic return type.</p>
<p>If you run mypy on this updated code, it will pass! Good job!</p>
<h2>What About PEP 695?</h2>
<p><a href="https://peps.python.org/pep-0695/" rel="">PEP 695</a> adds a new wrinkle to adding type hints to decorators by updating the parameter specification in Python in 3.12.</p>
<p>The main thrust of this PEP is to “simplify” the way you specify type parameters within a generic class, function, or type alias.</p>
<p>In a lot of ways, it does clean up the code as you no longer need to import ParamSpec of TypeVar when using this new syntax. Instead, it feels almost magical.</p>
<p>Here’s the updated code:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">from functools import wraps
from typing import Callable


def info[**P, R](func: Callable[P, R]) -&gt; Callable[P, R]:
    @wraps(func)
    def wrapper(*args: P.args, **kwargs: P.kwargs) -&gt; R:
        print('Function name: ' + func.__name__)
        print('Function docstring: ' + str(func.__doc__))
        return func(*args, **kwargs)
    return wrapper

@info
def doubler(number: int) -&gt; int:
    """Doubles the number passed to it"""
    return number * 2

print(doubler(4))</pre>
<p>Notice that at the beginning of the function you have square brackets. That is basically declaring your ParamSpec implicitly. The “R” is again the return type. The rest of the code is the same as before.</p>
<p>When you run mypy against this version of the type hinted decorator, you will see that it passes happily.</p>
<h2>Wrapping Up</h2>
<p>Type hinting can still be a hairy subject, but the newer the Python version that you use, the better the type hinting capabilities are.</p>
<p>Of course, since Python itself doesn’t enforce type hinting, you can just skip all this too. But if your employer like type hinting, hopefully this article will help you out.</p>
<h2>Related Reading</h2>
<ul>
<li>Learn all about decorators in <a href="https://blog.pythonlibrary.org/2017/07/18/python-all-about-decorators/">this sister article</a></li>
</ul>
</div>
</div>
</div>
</figure>
</div>
<p>The post <a href="https://blog.pythonlibrary.org/2026/01/14/how-to-type-hint-a-decorator-in-python/">How to Type Hint a Decorator in Python</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Switch to ty from Mypy</title>
		<link>https://blog.pythonlibrary.org/2026/01/09/how-to-switch-to-ty-from-mypy/</link>
		
		<dc:creator><![CDATA[Mike]]></dc:creator>
		<pubDate>Fri, 09 Jan 2026 15:16:16 +0000</pubDate>
				<category><![CDATA[beginner]]></category>
		<category><![CDATA[intermediate]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Type Checking]]></category>
		<guid isPermaLink="false">https://blog.pythonlibrary.org/?p=12738</guid>

					<description><![CDATA[<p>Python has supported type hinting for quite a few versions now, starting way back in 3.5. However, Python itself does not enforce type checking. Instead, you need to use an external tool or IDE. The first and arguably most popular is mypy. Microsoft also has a Python type checker that you can use in VS Code [&#8230;]</p>
<p>The post <a href="https://blog.pythonlibrary.org/2026/01/09/how-to-switch-to-ty-from-mypy/">How to Switch to ty from Mypy</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Python has supported type hinting for quite a few versions now, starting way back in 3.5. However, Python itself does not enforce type checking. Instead, you need to use an external tool or IDE. The first and arguably most popular is <a href="https://mypy.readthedocs.io/en/stable/index.html" rel="">mypy</a>.</p>
<p>Microsoft also has a Python type checker that you can use in VS Code called <a href="https://github.com/microsoft/pyright" rel="">Pyright,</a> and then there’s the lesser-known <a href="https://pyrefly.org/" rel="">Pyrefly</a> type checker and language server.</p>
<p>The newest type checker on the block is <a href="https://astral.sh/blog/ty" rel="">Astral&#8217;s ty</a>, the maker of Ruff. Ty is another super-fast Python utility written in Rust.</p>
<p>In this article, you will learn how to switch your project to use ty locally and in GitHub Actions.</p>
<h2 class="header-anchor-post">Installation</h2>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA">
<p><span style="font-size: 16px;">You can run ty with uvx if you do not want to install it by using the following command in your terminal: </span><strong style="font-size: 16px;">uvx ty</strong></p>
</div>
</div>
<p>To install ty with uv, run the following:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">uv tool install ty@latest</pre>
<p>If you do not want to use uv, you can use the standalone installer. Instructions vary depending on your platform, so it is best to refer to the <a href="https://docs.astral.sh/ty/installation/#installing-with-the-standalone-installer" rel="">documentation </a>for the latest information.</p>
<p>Note: Technically, you can use pip or pipx to install ty as well.</p>
<h2 class="header-anchor-post">Running ty Locally</h2>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA"><span style="font-size: 16px;">Once you have ty installed, you can run it using any of the following:</span></div>
</div>
<h3 class="header-anchor-post">Running with uv</h3>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA">
<pre class="EnlighterJSRAW" data-enlighter-language="generic">uv run ty</pre>
<p><span style="font-size: 1.5em; font-weight: bold;">Running without Installation</span></p>
</div>
</div>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA">
<pre class="EnlighterJSRAW" data-enlighter-language="generic">uvx ty</pre>
<p><span style="font-size: 1.5em; font-weight: bold;">Running ty Directly</span></p>
</div>
</div>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA">
<pre class="EnlighterJSRAW" data-enlighter-language="generic">ty check</pre>
<p><span style="font-size: 1.7em; font-weight: bold;">Configuring ty</span></p>
</div>
</div>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA"><span style="font-size: 16px;">You can configure ty using either of the following:</span></div>
</div>
<ul>
<li>pyproject.toml</li>
<li>ty.toml</li>
</ul>
<p>There are many rules that you can change. Check out the <a href="https://docs.astral.sh/ty/rules/" rel="">documentation</a> for full details.</p>
<p>In general, if you run mypy in strict mode, then running ty without changing any of its settings is very similar. However, ty currently does not highlight missing type hints. If you need to enforce adding type hints, you can use <a href="https://docs.astral.sh/ruff/rules/#flake8-annotations-ann" rel="">Ruff’s flake8-annotations</a>.</p>
<p>Here is how to enable the flak8-annotations in your <strong>pyproject.toml</strong> file:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-12739" src="https://blog.pythonlibrary.org/wp-content/uploads/2026/01/ruff_flake8.png" alt="Using Flake8 annotations in Ruff" width="1226" height="428" srcset="https://blog.pythonlibrary.org/wp-content/uploads/2026/01/ruff_flake8.png 1226w, https://blog.pythonlibrary.org/wp-content/uploads/2026/01/ruff_flake8-300x105.png 300w, https://blog.pythonlibrary.org/wp-content/uploads/2026/01/ruff_flake8-1024x357.png 1024w, https://blog.pythonlibrary.org/wp-content/uploads/2026/01/ruff_flake8-768x268.png 768w" sizes="auto, (max-width: 1226px) 100vw, 1226px" /></p>
<p>If you have other rules already selected, you can add “ANN” to the end of the list to enable it.</p>
<h2 class="header-anchor-post">Running ty in GitHub Actions</h2>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA"><span style="font-size: 16px;">Running ty in GitHub Actions is a great, free way to type-check your PRs. To add ty to GitHub Actions, create a new file named </span><strong style="font-size: 16px;">ty.yml</strong><span style="font-size: 16px;"> in your GitHub repo in the following location:</span></div>
</div>
<p><strong>.github/workflows/ty.yml</strong></p>
<p>Make sure you include the leading period!</p>
<p>Next, inside your yaml file, you will add the following code:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="yaml">name: ty
on:
  pull_request:
    types: [opened, synchronize, reopened, ready_for_review]
  workflow_dispatch:
jobs:
  build:
    if: github.event.pull_request.draft == false
    runs-on: self-hosted
    steps:
      - uses: actions/checkout@v3
      - name: Install Python
        uses: actions/setup-python@v4
        with:
          python-version: “3.12”
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install ty==0.0.7      
      - name: Run ty
        run: ty check
        continue-on-error: false</pre>
<p>Now, when your team opens a new PR in your project, it will automatically run ty against it. Feel free to update the Python version to the one you are using. Also note that this GitHub Action sets the ty version to 0.0.7, which you may need to update as newer releases become available.</p>
<h2 class="header-anchor-post">Using ty with pre-commit</h2>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA"><span style="font-size: 16px;">The ty project does not have official support for </span><a style="font-size: 16px; background-color: #ffffff;" href="https://pre-commit.com/" rel="">pre-commit</a><span style="font-size: 16px;"> yet. However, there is a </span><a style="font-size: 16px; background-color: #ffffff;" href="https://github.com/astral-sh/ty/issues/269" rel="">ticket </a><span style="font-size: 16px;">to add this functionality. In the meantime, several other people have provided their own workarounds to allow you to use ty with pre-commit:</span></div>
</div>
<ul>
<li><a href="https://github.com/NSPC911/ty-pre-commit" rel="">https://github.com/NSPC911/ty-pre-commit</a></li>
<li><a href="https://github.com/JacobCoffee/ty-pre-commit" rel="">https://github.com/JacobCoffee/ty-pre-commit</a></li>
<li><a href="https://github.com/hoxbro/ty-pre-commit" rel="">https://github.com/hoxbro/ty-pre-commit</a></li>
<li><a href="https://github.com/allganize/ty-pre-commit" rel="">https://github.com/allganize/ty-pre-commit</a></li>
<li><a href="https://foundry.fsky.io/vel/ty-pre-commit" rel="">https://foundry.fsky.io/vel/ty-pre-commit</a></li>
</ul>
<p>When Astral supports pre-commit itself, you should update your pre-commit configuration accordingly.</p>
<p>However, for this tutorial, you can use that first link which tells you to add the following to your <code>.pre-commit-config.yaml</code>:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-12740" src="https://blog.pythonlibrary.org/wp-content/uploads/2026/01/ty-pre-commit.png" alt="Using ty in pre-commit" width="1226" height="640" srcset="https://blog.pythonlibrary.org/wp-content/uploads/2026/01/ty-pre-commit.png 1226w, https://blog.pythonlibrary.org/wp-content/uploads/2026/01/ty-pre-commit-300x157.png 300w, https://blog.pythonlibrary.org/wp-content/uploads/2026/01/ty-pre-commit-1024x535.png 1024w, https://blog.pythonlibrary.org/wp-content/uploads/2026/01/ty-pre-commit-768x401.png 768w" sizes="auto, (max-width: 1226px) 100vw, 1226px" /></p>
<p>Now, when you commit a file locally, pre-commit will run ty to check it for you automatically.</p>
<h2 class="header-anchor-post">Wrapping Up</h2>
<div class="pencraft pc-display-flex pc-alignItems-center pc-position-absolute pc-reset header-anchor-parent">
<div class="pencraft pc-display-contents pc-reset pubTheme-yiXxQA">
<p><span style="font-size: 16px;">Type checkers can be really helpful in finding subtle bugs in your Python code. However, remembering to run them before pushing your code can be difficult, so make your life easier by adding the type checker to your CI!</span></p>
<p>&nbsp;</p>
</div>
</div>
<p>Have fun and happy coding!</p>
<p>The post <a href="https://blog.pythonlibrary.org/2026/01/09/how-to-switch-to-ty-from-mypy/">How to Switch to ty from Mypy</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ANN: Vibe Coding Video Games with Python</title>
		<link>https://blog.pythonlibrary.org/2025/12/01/ann-vibe-coding-video-games-with-python/</link>
		
		<dc:creator><![CDATA[Mike]]></dc:creator>
		<pubDate>Mon, 01 Dec 2025 16:11:24 +0000</pubDate>
				<category><![CDATA[beginner]]></category>
		<category><![CDATA[Books]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[AI]]></category>
		<guid isPermaLink="false">https://blog.pythonlibrary.org/?p=12725</guid>

					<description><![CDATA[<p>I am happy to announce my latest book, Vibe Coding Video Games with Python. Here&#8217;s the announcement from my Kickstarter: Welcome to Vibe Coding Video Games with Python. In this book, you will learn how to use artificial intelligence to create mini-games. You will attempt to recreate the look and feel of various classic video [&#8230;]</p>
<p>The post <a href="https://blog.pythonlibrary.org/2025/12/01/ann-vibe-coding-video-games-with-python/">ANN: Vibe Coding Video Games with Python</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I am happy to announce my latest book, <a href="https://www.kickstarter.com/projects/driscollis/vibe-coding-video-games-with-python">Vibe Coding Video Games with Python</a>. Here&#8217;s the announcement from my Kickstarter:</p>
<p>Welcome to <strong>Vibe Coding Video Games with Python</strong>. In this book, you will learn how to use artificial intelligence to create mini-games. You will attempt to recreate the look and feel of various classic video games. The intention is not to violate copyright or anything of the sort, but instead to learn the limitations and the power of AI.</p>
<p>Instead, you will simply be learning about whether or not you can use AI to help you know how to create video games. Can you do it with no previous knowledge, as the AI proponents say? Is it really possible to create something just by writing out questions to the ether?</p>
<p><strong>Release date: January 2026 (eBook) / March 2026 (paperback)</strong></p>
<p>You will be using various large language models (LLMs) such as Google Gemini, Grok, Mistral, CoPilot, and others to create these games. You will discover the differences and similarities between these tools. You may be surprised to find that some tools give much more context than others.</p>
<p>AI is certainly not a cure-all and is far from perfect. You will quickly discover AI&#8217;s limitations and learn some strategies for solving those kinds of issues.</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-12726 size-medium" src="https://blog.pythonlibrary.org/wp-content/uploads/2025/12/vibe_coding_cover-188x300.png" alt="" width="188" height="300" srcset="https://blog.pythonlibrary.org/wp-content/uploads/2025/12/vibe_coding_cover-188x300.png 188w, https://blog.pythonlibrary.org/wp-content/uploads/2025/12/vibe_coding_cover-642x1024.png 642w, https://blog.pythonlibrary.org/wp-content/uploads/2025/12/vibe_coding_cover-768x1225.png 768w, https://blog.pythonlibrary.org/wp-content/uploads/2025/12/vibe_coding_cover-963x1536.png 963w, https://blog.pythonlibrary.org/wp-content/uploads/2025/12/vibe_coding_cover-1283x2048.png 1283w, https://blog.pythonlibrary.org/wp-content/uploads/2025/12/vibe_coding_cover-scaled.png 1604w" sizes="auto, (max-width: 188px) 100vw, 188px" /></p>
<p>Here are some examples of what you will be creating in this book:</p>
<h4><strong>Lune Lander Clone</strong></h4>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-12727" src="https://blog.pythonlibrary.org/wp-content/uploads/2025/12/luna_lander.gif" alt="" width="792" height="626" /></p>
<h4>Asteroids Clone</h4>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-12728" src="https://blog.pythonlibrary.org/wp-content/uploads/2025/12/asteroids.gif" alt="" width="792" height="626" /></p>
<h4>Pong Clone</h4>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-12729" src="https://blog.pythonlibrary.org/wp-content/uploads/2025/12/pong.gif" alt="" width="802" height="626" /></p>
<h3><strong>What You&#8217;ll Learn</strong></h3>
<p>You&#8217;ll be creating &#8220;clones&#8221; of some popular games. However, these games will only be the first level and may or may not be fully functional.</p>
<ul>
<li>Chapter 1 &#8211; The Snake Game</li>
<li>Chapter 2 &#8211; Pong Clone</li>
<li>Chapter 3 &#8211; Frogger Clone</li>
<li>Chapter 4 &#8211; Space Invaders Clone</li>
<li>Chapter 5 &#8211; Minesweeper Clone</li>
<li>Chapter 6 &#8211; Luna Lander Clone</li>
<li>Chapter 7 &#8211; Asteroids Clone</li>
<li>Chapter 8 &#8211; Tic-Tac-Toe</li>
<li>Chapter 9 &#8211; Pole Position Clone</li>
<li>Chapter 10 &#8211; Connect Four</li>
<li>Chapter 11 &#8211; Intro to Sprites</li>
</ul>
<h3><strong>Rewards to Choose From</strong></h3>
<p>There are several different rewards you can get in this Kickstarter:</p>
<ul>
<li>A signed paperback copy of the book</li>
<li>An eBook copy of the book in PDF and ePub</li>
<li>A t-shirt with the cover art from the book</li>
<li>Other Python eBooks</li>
</ul>
<h2><a href="https://www.kickstarter.com/projects/driscollis/vibe-coding-video-games-with-python">Support the Kickstarter Today</a></h2>
<p>The post <a href="https://blog.pythonlibrary.org/2025/12/01/ann-vibe-coding-video-games-with-python/">ANN: Vibe Coding Video Games with Python</a> appeared first on <a href="https://blog.pythonlibrary.org">Mouse Vs Python</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
