Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions docs/collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class diagram panel
print(species) # ["burmese", "carpet", "ball", "blood"]
```

- **Acccess a range of multiple items at once:**
- **Access a range of multiple items at once:**

- **Slice with `list[start:end]`** to return a new list containing items from the `start` index up to (but not including) the `end` index.

Expand Down Expand Up @@ -333,6 +333,20 @@ class diagram panel

### Going further { data-card-link="skip" }

??? warning "In-place list methods return None"
`append()`, `insert()`, `extend()`, `sort()`, `reverse()`, and `remove()` all change the list directly and return `None` — not the changed list. Reassigning the variable to one of their results replaces the list itself with `None`, and the next call on it raises `AttributeError: 'NoneType' object has no attribute '...'`.

```python-ref
species = species.append("carpet") # species is now None, not the updated list
species.sort() # AttributeError: 'NoneType' object has no attribute 'sort'
```

Call the method on its own line instead — the list was already changed in place, nothing to reassign.

```python-ref
species.append("carpet") # correct — no assignment needed
```

??? run "Practice with lists"
Each box below is fully editable — write your answer, then click Run.

Expand Down Expand Up @@ -485,7 +499,7 @@ flowchart LR
snake["species"] # "ball"
```

- **`get()`** does the same thing, but returns `None` if the key is not in the dict. You can provide an optinal default value to fall back on that will be returned if they key is not in the dict.
- **`get()`** does the same thing, but returns `None` if the key is not in the dict. You can provide an optional default value to fall back on that will be returned if the key is not in the dict.

```python-ref
snake.get("species") # "ball"
Expand Down
427 changes: 248 additions & 179 deletions docs/errors.md

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions docs/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,28 @@ describe(species="ball", venomous=True) # length_ft still uses its default
pass # placeholder — does nothing, but prevents a syntax error
```

??? warning "Mutable default argument"
A default value is only ever created **once**, when the function is defined — not fresh on every call. For a list or dict default, that means every call sharing that default is silently reading and writing the *same* object, so it keeps growing across calls instead of starting empty each time.

```python-ref
def add_sighting(species, log=[]): # log=[] is created once, not per call
log.append(species)
return log

add_sighting("ball") # ["ball"]
add_sighting("burmese") # ["ball", "burmese"] — the same list, not a fresh one
```

Default to `None` instead, and create the list inside the function body:

```python-ref
def add_sighting(species, log=None):
if log is None:
log = []
log.append(species)
return log
```

??? run "Run a function example"
All the examples above, combined into one script:

Expand Down
70 changes: 46 additions & 24 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ hide:

[**`Terminal application`**](workspace.md#using-the-terminal-optional)

[**`virtual environments`**](workspace.md#virtual-environments-optional)

- :material-cube-outline:{ .lg .middle } [__Foundations__](foundations.md)

Storing, displaying, and inputting values.
Expand Down Expand Up @@ -102,7 +104,7 @@ hide:

Repeat a block of code multiple times.

[**`for`**](loops.md#for-loops): [`enumerate`](loops.md#loop-with-index-and-value) [`loop a set number of times`](loops.md#loop-a- certain-number-of-times) [`loop through a collection`](loops.md#loop-through-a-collection) [`range`](loops.md#iterable-range) [`reversed`](loops.md#loop-in-reverse) [`zip`](loops.md#loop-with-index-and-value)
[**`for`**](loops.md#for-loops): [`enumerate`](loops.md#loop-with-index-and-value) [`loop a set number of times`](loops.md#loop-a-certain-number-of-times) [`loop through a collection`](loops.md#loop-through-a-collection) [`range`](loops.md#iterable-range) [`reversed`](loops.md#loop-in-reverse) [`zip`](loops.md#loop-with-index-and-value)

[**`while`**](loops.md#while-loops): [`and`](loops.md#logical-operators) [`boolean expressions`](loops.md#boolean-expressions) [`counter and flag names`](loops.md#counter-and-flag-names) [`flag`](loops.md#using-a-flag) [`not`](loops.md#logical-operators) [`or`](loops.md#logical-operators) [`sentinel`](loops.md#sentinel)

Expand All @@ -124,7 +126,7 @@ hide:

[**`def`**](functions.md#defining-a-function): [`default parameter values`](functions.md#default-parameter-values) [`docstrings`](functions.md#docstrings) [`keyword arguments`](functions.md#keyword-arguments) [`return`](functions.md#return-values)

[**`*args`**](functions.md#args), [**`**kwargs`**](functions.md#kwargs)
[**`flexible arguments`**](functions.md#flexible-arguments): [`*args`](functions.md#args) [`**kwargs`](functions.md#kwargs)

[**`scope`**](functions.md#scope): [`local vs global`](functions.md#local-vs-global-variables)

Expand Down Expand Up @@ -196,13 +198,11 @@ hide:

How to understand, manage, and fix errors.

[**`try, except`**](errors.md#handling-errors): [`exception types`](errors.md#common-exception-types)

[**`tracebacks`**](errors.md#reading-errors): [`how to read a traceback`](errors.md#how-to-read-a-traceback)
[**`kinds of errors`**](errors.md#kinds-of-errors): [`syntax errors`](errors.md#syntax-errors) [`runtime errors`](errors.md#runtime-errors) [`logic errors`](errors.md#logic-errors)

[**`debugger`**](errors.md#using-a-debugger): [`run in debug mode`](errors.md#step-1-run-in-debug-mode) [`set breakpoints`](errors.md#step-0-set-breakpoints) [`what you can do at a breakpoint`](errors.md#step-2-what-you-can-do-at-a-breakpoint)
[**`fixing errors`**](errors.md#fixing-errors): [`tracebacks`](errors.md#reading-a-traceback) [`reading a syntax error message`](errors.md#reading-a-syntax-error-message) [`try, except`](errors.md#catch-with-tryexcept) [`debugging strategies`](errors.md#debugging-strategies) [`isolate the problem`](errors.md#isolate-the-problem) [`print debugging`](errors.md#print-debugging) [`rubber duck debugging`](errors.md#read-it-out-loud) [`debugger tool`](errors.md#debugger-tool) [`TODO, FIXME`](errors.md#flag-as-todofixme) [`testing`](errors.md#detect-errors-with-testing)

[**`debugging strategies`**](errors.md#debugging-strategies): [`isolate the problem`](errors.md#isolate-the-problem) [`print debugging`](errors.md#print-debugging) [`rubber duck debugging`](errors.md#read-it-out-loud) [`TODO, FIXME`](errors.md#flag-it-with-todofixme)
[**`detect errors with testing`**](errors.md#detect-errors-with-testing)

</div>
</div>
Expand Down Expand Up @@ -252,31 +252,23 @@ hide:
</div>

<div class="pt-category pt-category--wide pt-lib--1" markdown="block">
#### Desktop UIs { .pt-homepage-heading }
#### Testing { .pt-homepage-heading }

<div class="grid cards" markdown="block">

- :material-application-outline:{ .lg .middle } [__Tkinter__](libraries/tkinter.md) [:material-language-python:](libraries/tkinter.md){ .pt-lib-badge .pt-lib-badge--builtin title="Built-in — included with Python" }

Creating desktop applications: text, buttons, dropdowns, forms, output, etc.

[**`Tk`**](libraries/tkinter.md#creating-a-window)

[**`Button`**](libraries/tkinter.md#widgets): [`Button`](libraries/tkinter.md#button) [`Entry`](libraries/tkinter.md#entry) [`Label`](libraries/tkinter.md#label)

[**`pack`**](libraries/tkinter.md#layout-managers): [`grid`](libraries/tkinter.md#grid) [`pack`](libraries/tkinter.md#pack)
- :material-test-tube:{ .lg .middle } [__pytest__](libraries/pytest.md) [:material-download-outline:](libraries/pytest.md){ .pt-lib-badge .pt-lib-badge--third-party title="Third-party — install separately with pip" }

[**`configure`**](libraries/tkinter.md#configuring-widgets): [`reading and changing options`](libraries/tkinter.md#reading-and-changing-options)
Writing and running tests: assertions, fixtures, and parametrizing.

[**`command`**](libraries/tkinter.md#handling-events): [`binding events`](libraries/tkinter.md#binding-events) [`command callbacks`](libraries/tkinter.md#command-callbacks)
[**`writing and running a test`**](libraries/pytest.md#writing-and-running-a-test): [`from the command line`](libraries/pytest.md#from-the-command-line)

[**`Style`**](libraries/tkinter.md#styling-with-ttk): [`customizing a style`](libraries/tkinter.md#customizing-a-style)
[**`reading a failure`**](libraries/pytest.md#reading-a-failure)

[**`messagebox`**](libraries/tkinter.md#dialogs): [`file dialogs`](libraries/tkinter.md#file-dialogs) [`message boxes`](libraries/tkinter.md#message-boxes)
[**`fixtures`**](libraries/pytest.md#fixtures)

[**`winfo_width`**](libraries/tkinter.md#introspecting-widgets): [`winfo methods`](libraries/tkinter.md#winfo-methods)
[**`parametrizing tests`**](libraries/pytest.md#parametrizing-tests)

[**`putting it together`**](libraries/tkinter.md#putting-it-together): [`a simple form`](libraries/tkinter.md#a-simple-form)
[**`testing for exceptions`**](libraries/pytest.md#testing-for-exceptions)

</div>
</div>
Expand Down Expand Up @@ -389,6 +381,36 @@ hide:
</div>
</div>

<div class="pt-category pt-category--wide pt-lib--1" markdown="block">
#### Desktop UIs { .pt-homepage-heading }

<div class="grid cards" markdown="block">

- :material-application-outline:{ .lg .middle } [__Tkinter__](libraries/tkinter.md) [:material-language-python:](libraries/tkinter.md){ .pt-lib-badge .pt-lib-badge--builtin title="Built-in — included with Python" }

Creating desktop applications: text, buttons, dropdowns, forms, output, etc.

[**`Tk`**](libraries/tkinter.md#creating-a-window)

[**`Button`**](libraries/tkinter.md#widgets): [`Button`](libraries/tkinter.md#button) [`Entry`](libraries/tkinter.md#entry) [`Label`](libraries/tkinter.md#label)

[**`pack`**](libraries/tkinter.md#layout-managers): [`grid`](libraries/tkinter.md#grid) [`pack`](libraries/tkinter.md#pack)

[**`configure`**](libraries/tkinter.md#configuring-widgets): [`reading and changing options`](libraries/tkinter.md#reading-and-changing-options)

[**`command`**](libraries/tkinter.md#handling-events): [`binding events`](libraries/tkinter.md#binding-events) [`command callbacks`](libraries/tkinter.md#command-callbacks)

[**`Style`**](libraries/tkinter.md#styling-with-ttk): [`customizing a style`](libraries/tkinter.md#customizing-a-style)

[**`messagebox`**](libraries/tkinter.md#dialogs): [`file dialogs`](libraries/tkinter.md#file-dialogs) [`message boxes`](libraries/tkinter.md#message-boxes)

[**`winfo_width`**](libraries/tkinter.md#introspecting-widgets): [`winfo methods`](libraries/tkinter.md#winfo-methods)

[**`putting it together`**](libraries/tkinter.md#putting-it-together): [`a simple form`](libraries/tkinter.md#a-simple-form)

</div>
</div>

<div class="pt-category pt-category--wide pt-lib--1" markdown="block">
#### Computer vision { .pt-homepage-heading }

Expand Down Expand Up @@ -430,7 +452,7 @@ hide:
| | Learn to do it yourself | Have AI do it for you |
|---|---|---|
| **Writing & struggling with code** | :material-check:{ .pt-icon-success } **Productive struggle** is what builds understanding<ul><li>You can solve the problem again on your own</li><li>Adapt the answer, and catch when it's wrong</li></ul> | :material-close:{ .pt-icon-fail } Being handed the answer skips [the friction that builds understanding](https://bjorklab.psych.ucla.edu/wp-content/uploads/sites/13/2016/04/EBjork_RBjork_2011.pdf)<ul><li>If you skip that struggle, you *won't develop the knowledge* to solve the problem again, adapt the answer, or recognize when it's wrong.</li></ul> |
| **Reading & verifying code** | :material-check:{ .pt-icon-success } Understanding programming fundamentals makes AI more useful — you can read code you didn't write, and check it before you trust it<ul><li>Spot mistakes</li><li>Understand *why* a solution works</li><li>Communicate your problem to AI more effectively</li></ul> | :material-close:{ .pt-icon-fail } Inefficient communciation with AI if you don't fully understand what's going on, and AI code can look correct while being **wrong and insecure**<ul><li>You can't tell *why* a solution works</li><li>Researchers are already documenting this skill gap in [students who rely on AI code generation](https://dl.acm.org/doi/10.1145/3617367) before they've [built their own foundation](https://dl.acm.org/doi/10.1145/3624720)</li><li>One [Stanford study](https://dl.acm.org/doi/10.1145/3576915.3623157) found developers using AI wrote *less* secure code — but were *more* confident it was secure</li></ul> |
| **Reading & verifying code** | :material-check:{ .pt-icon-success } Understanding programming fundamentals makes AI more useful — you can read code you didn't write, and check it before you trust it<ul><li>Spot mistakes</li><li>Understand *why* a solution works</li><li>Communicate your problem to AI more effectively</li></ul> | :material-close:{ .pt-icon-fail } Inefficient communication with AI if you don't fully understand what's going on, and AI code can look correct while being **wrong and insecure**<ul><li>You can't tell *why* a solution works</li><li>Researchers are already documenting this skill gap in [students who rely on AI code generation](https://dl.acm.org/doi/10.1145/3617367) before they've [built their own foundation](https://dl.acm.org/doi/10.1145/3624720)</li><li>One [Stanford study](https://dl.acm.org/doi/10.1145/3576915.3623157) found developers using AI wrote *less* secure code — but were *more* confident it was secure</li></ul> |
| **On the job** | :material-check:{ .pt-icon-success } Employers are still hiring for understanding, not prompting<ul><li>Code review, debugging, and interviews all test whether you can reason about code</li><li>And judge whether it's correct</li><li>Learning to program on your own turns AI into a tool you can direct and verify, instead of one you're assuming got it right</li></ul> | :material-close:{ .pt-icon-fail } AI will likely be available at work too — but it isn't what's being tested |

</div>
Expand Down
6 changes: 3 additions & 3 deletions docs/javascripts/pyodide_runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@
const pyodide = await loadPyodideRuntime();

// Pure-stdlib code runs as-is, but third-party packages (numpy,
// pandas, ...) ship as separate Pyodide wheels that must be fetched
// before the `import` inside the snippet will succeed.
// pandas, pytest, ...) ship as separate Pyodide wheels that must be
// fetched before the `import` inside the snippet will succeed.
const source = codeBlock.textContent;
const neededPackages = ["numpy", "pandas"].filter((pkg) =>
const neededPackages = ["numpy", "pandas", "pytest"].filter((pkg) =>
new RegExp(`\\bimport\\s+${pkg}\\b|\\bfrom\\s+${pkg}\\b`).test(source)
);
if (neededPackages.length) {
Expand Down
2 changes: 1 addition & 1 deletion docs/libraries/collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ description: >-
`from collections import ...`. For the built-in `list`, `dict`, `tuple`, and `set` types
themselves, see [Collections](../collections.md).

The **`collections`** module adds specialized containers with added functionaility on top of the
The **`collections`** module adds specialized containers with added functionality on top of the
built-in [`str`](../types.md#strings) [`list`](../collections.md#lists) [`dict`](../collections.md#dictionaries) [`tuple`](../collections.md#tuples) and [`set`](../collections.md#sets).

<div class="pt-jump-table" markdown="block">
Expand Down
54 changes: 38 additions & 16 deletions docs/libraries/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,31 +54,23 @@ Libraries allow us to apply Python to real tasks. These are a few popular ones,
</div>

<div class="pt-category pt-category--wide pt-lib--1" markdown="block">
#### Desktop UIs { .pt-homepage-heading }
#### Testing { .pt-homepage-heading }

<div class="grid cards" markdown="block">

- :material-application-outline:{ .lg .middle } [__Tkinter__](tkinter.md) [:material-language-python:](tkinter.md){ .pt-lib-badge .pt-lib-badge--builtin title="Built-in — included with Python" }

Creating desktop applications: text, buttons, dropdowns, forms, output, etc.

[**`Tk`**](tkinter.md#creating-a-window)
- :material-test-tube:{ .lg .middle } [__pytest__](pytest.md) [:material-download-outline:](pytest.md){ .pt-lib-badge .pt-lib-badge--third-party title="Third-party — install separately with pip" }

[**`Button`**](tkinter.md#widgets): [`Button`](tkinter.md#button) [`Entry`](tkinter.md#entry) [`Label`](tkinter.md#label)
Writing and running tests: assertions, fixtures, and parametrizing.

[**`pack`**](tkinter.md#layout-managers): [`grid`](tkinter.md#grid) [`pack`](tkinter.md#pack)
[**`writing and running a test`**](pytest.md#writing-and-running-a-test): [`from the command line`](pytest.md#from-the-command-line)

[**`configure`**](tkinter.md#configuring-widgets): [`reading and changing options`](tkinter.md#reading-and-changing-options)
[**`reading a failure`**](pytest.md#reading-a-failure)

[**`command`**](tkinter.md#handling-events): [`binding events`](tkinter.md#binding-events) [`command callbacks`](tkinter.md#command-callbacks)
[**`fixtures`**](pytest.md#fixtures)

[**`Style`**](tkinter.md#styling-with-ttk): [`customizing a style`](tkinter.md#customizing-a-style)
[**`parametrizing tests`**](pytest.md#parametrizing-tests)

[**`messagebox`**](tkinter.md#dialogs): [`file dialogs`](tkinter.md#file-dialogs) [`message boxes`](tkinter.md#message-boxes)

[**`winfo_width`**](tkinter.md#introspecting-widgets): [`winfo methods`](tkinter.md#winfo-methods)

[**`putting it together`**](tkinter.md#putting-it-together): [`a simple form`](tkinter.md#a-simple-form)
[**`testing for exceptions`**](pytest.md#testing-for-exceptions)

</div>
</div>
Expand Down Expand Up @@ -191,6 +183,36 @@ Libraries allow us to apply Python to real tasks. These are a few popular ones,
</div>
</div>

<div class="pt-category pt-category--wide pt-lib--1" markdown="block">
#### Desktop UIs { .pt-homepage-heading }

<div class="grid cards" markdown="block">

- :material-application-outline:{ .lg .middle } [__Tkinter__](tkinter.md) [:material-language-python:](tkinter.md){ .pt-lib-badge .pt-lib-badge--builtin title="Built-in — included with Python" }

Creating desktop applications: text, buttons, dropdowns, forms, output, etc.

[**`Tk`**](tkinter.md#creating-a-window)

[**`Button`**](tkinter.md#widgets): [`Button`](tkinter.md#button) [`Entry`](tkinter.md#entry) [`Label`](tkinter.md#label)

[**`pack`**](tkinter.md#layout-managers): [`grid`](tkinter.md#grid) [`pack`](tkinter.md#pack)

[**`configure`**](tkinter.md#configuring-widgets): [`reading and changing options`](tkinter.md#reading-and-changing-options)

[**`command`**](tkinter.md#handling-events): [`binding events`](tkinter.md#binding-events) [`command callbacks`](tkinter.md#command-callbacks)

[**`Style`**](tkinter.md#styling-with-ttk): [`customizing a style`](tkinter.md#customizing-a-style)

[**`messagebox`**](tkinter.md#dialogs): [`file dialogs`](tkinter.md#file-dialogs) [`message boxes`](tkinter.md#message-boxes)

[**`winfo_width`**](tkinter.md#introspecting-widgets): [`winfo methods`](tkinter.md#winfo-methods)

[**`putting it together`**](tkinter.md#putting-it-together): [`a simple form`](tkinter.md#a-simple-form)

</div>
</div>

<div class="pt-category pt-category--wide pt-lib--1" markdown="block">
#### Computer vision { .pt-homepage-heading }

Expand Down
Loading
Loading