Day 24 - Starting Python
Skills: 8
Pre-reading: 9.1.1, 9.1.2, 9.1.3, 9.1.4, 9.1.5
Supplementary Videos
NOTE: import pytest is not needed anymore!
Functions and Conditionals in Python
Python in vscode.dev (10 mins)
Today we begin our transition to Python. We will still use vscode.dev: you do not need to install Python on your computer. Instead, we use an extension called Python Language Levels (PLL). It runs Python in the browser, the same way the Pyret extension runs Pyret.
Unlike Pyret, the output shows up in a separate interactions panel at the bottom of the screen, rather than being up at the side.
Install the extension
- Open your
cs2000-scratchrepository in vscode.dev the way you have all semester: on GitHub, view the repository and press.(or go tohttps://vscode.dev/github/YOURUSERNAME/cs2000-scratch). - Click the Extensions icon in the left sidebar (the four squares).
- Search for Python Language Levels.
- Click Install. If it asks you to trust the publisher, do that.
- If vscode.dev offers to install Microsoft's Python extension, don't. We are using Python Language Levels, not that one. If you already installed it, you can ignore the extra prompts, or disable it for this workspace.
Create a Python file and run it
-
Make a new file named
24.py(same new-file icon you've used for.arrfiles). -
Put a small program in it, for example:
print("hello python") -
Look at the top right of the editor, on the same bar as the file name. Click PLL: Run Python File.
If you don't see it, open the Command Palette (
Ctrl+Shift+Pon Windows,Cmd+Shift+Pon a Mac) and run PLL: Run Python File. -
The first run can take a little while: PLL is loading Python in the browser. Later runs should be faster.
-
After it runs, look at the bottom of the window for a PLL panel (near Problems, Terminal, and so on). That panel is the interactions view: it shows
printoutput, values, and errors. Your.pyfile stays open above it — PLL does not replace the editor the way Pyret does.If the panel isn't visible, use the Command Palette and run PLL: Show Interactions.
-
The interactions view has a prompt at the bottom. After a file has been run, you can type extra expressions there (for example
1 + 1) and press Enter. Those run in the same session, so names you defined in the file are available.
Intro (20 mins)
Python and Pyret share many core ideas, but use different notation and conventions.
Example: defining a function
- Pyret:
fun gadget-cost(num-gadgets :: Number, label :: String) -> Number:
doc: "computes cost, at $0.50 per gadget plus $0.05 per character in label"
num-gadgets * (0.50 + (string-length(label) * 0.05))
where:
gadget-cost(1, "hi") is 0.60
gadget-cost(10, "tech") is 7.00
end - Python:
def gadget_cost(num_gadgets: int, label: str) -> float:
"""computes cost, at $0.50 per gadget plus $0.05 per character in label"""
return num_gadgets * (0.50 + (len(label) * 0.05))
Two differences to notice right away:
- Python uses
def, a colon, and indentation instead offun/end. - A Python function only gives a result if you
returnit. If you forgetreturn, the function producesNone.
Example: conditionals
- Pyret:
fun add-shipping(order-amt :: Number) -> Number:
doc: "adds 4 for orders <= 10 (but non-zero), 8 for orders < 30, 12 for larger orders"
if order-amt == 0:
0
else if order-amt <= 10:
order-amt + 4
else if order-amt < 30:
order-amt + 8
else:
order-amt + 12
end
end - Python:
def add_shipping(order_amt: float) -> float:
"""adds 4 for orders <= 10 (but non-zero), 8 for orders < 30, 12 for larger orders"""
if order_amt == 0:
return 0
elif order_amt <= 10:
return order_amt + 4
elif order_amt < 30:
return order_amt + 8
else:
return order_amt + 12
Python writes elif where Pyret writes else if, and each branch that should produce a result needs its own return.
Testing
In Pyret, examples live in a where: block on the function. In Python, you write tests in separate functions whose names begin with test_. Different Python environments have you place them in different places, but for us, with PLL, you place these functions in the same file as the code they check. Tests use assert to check a boolean expression.
Put this in 24.py along with gadget_cost:
import pytest
def test_gadget_cost_small() -> None:
assert gadget_cost(1, "hi") == pytest.approx(0.60)
def test_gadget_cost_medium() -> None:
assert gadget_cost(10, "tech") == pytest.approx(6.50)
# Intentionally wrong, so you can see a failing test
Then click PLL: Run Python File. PLL runs the tests first and shows a pass/fail card in the interactions view. Failed assertions are clickable and jump to the test. After the tests, it still runs the rest of the file, so names like gadget_cost are available at the interactions prompt.
Fix the expected value in test_gadget_cost_medium to 7.00 and run again so both tests pass.
Conventions:
- Test functions must be named starting with
test_. - Put tests in the same file as the functions they test. You do not need a separate
test_*.pyfile, and you do not runpytestin a terminal. - Use
assertto check expected results. If the expression isFalse, the test fails. - Prefer a single
assertper test function. A test stops at the first failing assertion. - For floating-point (decimal) results, use
pytest.approx, which is analogous to Pyret'sis-roughly. That requiresimport pytestat the top of the file.
Class Exercises (20 mins)
-
Function syntax. Rewrite the following Pyret function in Python. Follow the design recipe, including a docstring and tests in the same file.
fun greet(name :: String) -> String:
doc: "produces Hello, name!"
"Hello, " + name + "!"
where:
greet("Alice") is "Hello, Alice!"
greet("Bob") is "Hello, Bob!"
endThen design a Python function that takes a name and an age and returns a string like
"Alice is 20 years old." -
Conditionals. Translate this Pyret function to Python, with tests:
fun shipping-cost(weight :: Number) -> Number:
doc: "if weight <= 1, cost is $5; if weight <= 5, cost is $10; otherwise, $20"
if weight <= 1:
5
else if weight <= 5:
10
else:
20
end
end -
Return. What happens if you forget the
returnstatement in a Python function? Try it, write a test that shows the problem, and observe the result.