Previous: 10-DebuggingTesting.html
document.querySelector('video').playbackRate = 1.2
https://informationisbeautiful.net/visualizations/million-lines-of-code/
https://en.wikipedia.org/wiki/Programming_in_the_large_and_programming_in_the_small
For large projects, why is static typing often better than dynamic
typing?
* How do you know what your function returns?
* How do you know what types of object a function needs as
arguments?
* How do you learn 10,000,000 lines of code as quickly as
possible?
* You’ve just gotten your first job/internship, and you boss says:
“Here’s a giant project, fix a bug add a feature, get it back to me by
next week.”
* Static typing supports the human!
* The benefit is not necessarily in technical speed.
* Instead, it is good
https://en.wikipedia.org/wiki/Human_factors_and_ergonomics which can be
used to design a language that reduces the tendency for YOU to make an
error tends to be a better one.
* You can re-factor to new versions of a language more easily.
* Typing catches an entire class of bugs that don’t need to exist at
all!
* Helps code completion in IDEs too.
For small projects, what are the advantages of dynamic typing over
static?
* For example, in python (dynamic) versus C++ (static), we more easily
can write one function to operate on containers containing many types of
thing.
* See 03-IntroPython for our previous
discussion of “lines ratio” and expressiveness.
* The same program that might take you a week in Java or C++ could take
you an hour in python.
* Human time is, in general, far more valuable that computer time
(unless you aren’t a valuable employee…).
* The more prized employee saves their valuable time and implements
their solution in python, then delegating to a grunt, it’s conversion to
a faster language to a grunt.
* It’s the algorithmic decision making and design that is the deep,
respected, and hard-to-come-by skill that get’s the big $$
Another grand quote for the day:
**Mommy knows best.**
- my daughter
This moniker comes from the phrase “if it walks like a duck and it
quacks like a duck, then it must be a duck” (or any of its
variations).
* https://en.wikipedia.org/wiki/Type_system#Duck_typing
* https://en.wikipedia.org/wiki/Duck_typing
As an example, you can call len()
on any Python object
that defines a special ._len_()
method:
11-TypeHints/Ducky.py
#!/usr/bin/python3
# -*- coding: utf-8 -*-
class Ducky:
def _len_(self) -> int:
return 95022
a_duck = Ducky()
print(len(a_duck))
len()
gives the return value of
the ._len_()
method.len()
is essentially
equivalent to the following:len(obj)
, the only real constraint on
obj is that it must define a ._len_()
method.str
, list
, dict
,
Ducky
, or TheHobbit
.#!/usr/bin/python3
# -*- coding: utf-8 -*-
thing = "5"
# Just get type
# type(object)
print(type(thing))
# Check type and subtypes
if isinstance(thing, str):
print("object is instance of str")
# To check if the type of o is exactly str (exclude subclasses):]
if type(thing) is str:
print("object is str")
# The following also works, and can be useful in some cases:
if issubclass(type(thing), str):
print("object is sub-class of str")
$ mypy mycode.py
$ python3 mycode.py
, because python3 itself ignores the
type-hint comments, and thus misses an entire class of obvious,
auto-checkable bugs!The primary reference implementation of type hinting is
mypy
:
http://mypy-lang.org/
Install it this way in Linux if you have sudo
capability:
$ sudo zypper install python3-mypy mypy
$ sudo dnf install python3-mypy mypy
$ sudo apt install python3-mypy mypy
If you don’t have sudo
privileges (or are not running
Linux), install it this way:
$ pip3 install --upgrade mypy --user
This will check your script for type validity, and will do so with
even more strictness than the defaults:
$ mypy --strict --disallow-any-explicit myscript.py
This is what we expect in this class!
mypy
is the primary pre-run type-checker, but there are
others:
* https://www.bernat.tech/the-state-of-type-hints-in-python/
Note:
Python <3.9
Python >3.9
You can either write type-hints yourself, as you code, or have
monkeytype
write them for you after/during coding.
11-TypeHints/type_hint_00.py
(correct)
11-TypeHints/type_hint_01.py
(error)
11-TypeHints/type_hint_02.py
(an un-typed function)
Perform pre-execution type checks as:
$ mypy type_hint_0n.py
mypy
report an error if
you add a dynamically-typed function by mistake.--disallow-untyped-defs
flag.--strict
, which
enables many (though not all) of the available strictness options,
including --disallow-untyped-defs
$ mypy --disallow-untyped-defs type_hint_0n.py
$ mypy --disallow-any-explicit type_hint_0n.py
$ mypy --strict type_hint_0n.py
We will require this in all code from the time we give you the class
VM!
$ mypy --strict --disallow-any-explicit *.py
To auto-generate type hints on existing code base:
https://monkeytype.readthedocs.io/en/latest/index.html
#!/usr/bin/python3
# -*- coding: utf-8 -*-
def my_func(x):
return [x]
def main():
x = 5
my_func(x)
if _name_ == "_main_":
main()
#!/bin/bash
# To show it is not typed:
mypy --strict --disallow-any-explicit file_to_type.py
monkeytype run temp_wrapper.py
monkeytype apply file_to_type
# Run again to show it's typed now!
mypy --strict --disallow-any-explicit file_to_type.py
monkeytype
actually watches the values of the variables
passed to your functions as the code runs (it’s not just a static
analysis).
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# python <3.9
# from typing import List
# python <3.9
#def my_func(x: int) -> List[int]:
def my_func(x: int) -> list[int]:
return [x]
def main() -> None:
x: int = 5
my_func(x)
if _name_ == "_main_":
main()
Now, type-check it again:
#!/bin/bash
# To show it is correctly typed now:
mypy --strict --disallow-any-explicit file_to_type.py
stubgen myscript.py
Will create out/myscript.pyi
with types specified
separately
Note: we don’t bother with stubs in this class.
++++++++++++++++++
Cahoot-11.1
https://mst.instructure.com/courses/58101/quizzes/56078
++++++++++++++++++
Cahoot-11.2
https://mst.instructure.com/courses/58101/quizzes/56079
The example child’s game from the below book, we covered last class,
now typed and much easier to understand at quick glance:
https://en.wikipedia.org/wiki/Hangman_(game)
http://inventwithpython.com/invent4thed/chapter7.html
http://inventwithpython.com/invent4thed/chapter8.html
http://inventwithpython.com/invent4thed/chapter9.html
11-TypeHints/hangman.py (typed using python >3.9 type hints)
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import random
HANGMAN_PICS: list[str] = [
"""
+---+
|
|
|
===""",
"""
+---+
O |
|
|
===""",
"""
+---+
O |
| |
|
===""",
"""
+---+
O |
/| |
|
===""",
"""
+---+
O |
/|\ |
|
===""",
"""
+---+
O |
/|\ |
/ |
===""",
"""
+---+
O |
/|\ |
/ \ |
===""",
]
words: list[str] = (
"ant baboon badger bat bear beaver "
"camel cat clam cobra cougar coyote crow deer dog "
"donkey duck eagle ferret fox frog goat goose hawk "
"lion lizard llama mole monkey moose mouse mule newt "
"otter owl panda parrot pigeon python rabbit ram rat "
"raven rhino salmon seal shark sheep skunk sloth "
"snake spider stork swan tiger toad trout turkey "
"turtle weasel whale wolf wombat zebra"
).split()
# words: list[str] = [
# "ant",
# "baboon",
# "badger",
# "bat",
# "bear",
# "beaver",
# "camel",
# "cat",
# "clam",
# "cobra",
# "cougar",
# "coyote",
# "crow",
# "deer",
# "dog",
# "donkey",
# "duck",
# "eagle",
# "ferret",
# "fox",
# "frog",
# "goat",
# "goose",
# "hawk",
# "lion",
# "lizard",
# "llama",
# "mole",
# "monkey",
# "moose",
# "mouse",
# "mule",
# "newt",
# "otter",
# "owl",
# "panda",
# "parrot",
# "pigeon",
# "python",
# "rabbit",
# "ram",
# "rat",
# "raven",
# "rhino",
# "salmon",
# "seal",
# "shark",
# "sheep",
# "skunk",
# "sloth",
# "snake",
# "spider",
# "stork",
# "swan",
# "tiger",
# "toad",
# "trout",
# "turkey",
# "turtle",
# "weasel",
# "whale",
# "wolf",
# "wombat",
# "zebra",
# ]
def getRandomWord(wordList: list[str]) -> str:
# This function returns a random string from the passed list of strings.
wordIndex = random.randint(0, len(wordList) - 1)
return wordList[wordIndex]
def displayBoard(missedLetters: str, correctLetters: str, secretWord: str) -> None:
print(HANGMAN_PICS[len(missedLetters)])
print()
print("Missed letters:", end=" ")
for letter in missedLetters:
print(letter, end=" ")
print()
blanks = "_" * len(secretWord)
# replace blanks with correctly guessed letters
for i in range(len(secretWord)):
if secretWord[i] in correctLetters:
blanks = blanks[:i] + secretWord[i] + blanks[i + 1 :]
# show the secret word with spaces in between each letter
for letter in blanks:
print(letter, end=" ")
print()
def getGuess(alreadyGuessed: str) -> str:
# Returns the letter the player entered.
# This function makes sure the player entered a single letter,
# and not something else.
while True:
print("Guess a letter.")
guess = input()
guess = guess.lower()
if len(guess) != 1:
print("Please enter a single letter.")
elif guess in alreadyGuessed:
print("You have already guessed that letter. Choose again.")
elif guess not in "abcdefghijklmnopqrstuvwxyz":
print("Please enter a LETTER.")
else:
return guess
def playAgain() -> bool:
# This function returns True if the player wants to play again;
# otherwise, it returns False.
print("Do you want to play again? (yes or no)")
return input().lower().startswith("y")
def main() -> None:
print("H A N G M A N")
missedLetters = ""
correctLetters = ""
secretWord = getRandomWord(words)
gameIsDone = False
while True:
displayBoard(missedLetters, correctLetters, secretWord)
# Let the player enter a letter.
guess = getGuess(missedLetters + correctLetters)
if guess in secretWord:
correctLetters = correctLetters + guess
# Check if the player has won.
foundAllLetters = True
for i in range(len(secretWord)):
if secretWord[i] not in correctLetters:
foundAllLetters = False
break
if foundAllLetters:
print('Yes! The secret word is "' + secretWord + '"! You have won!')
gameIsDone = True
else:
missedLetters = missedLetters + guess
# Check if player has guessed too many times and lost.
if len(missedLetters) == len(HANGMAN_PICS) - 1:
displayBoard(missedLetters, correctLetters, secretWord)
print(
"You have run out of guesses!\nAfter "
+ str(len(missedLetters))
+ " missed guesses and "
+ str(len(correctLetters))
+ ' correct guesses, the word was "'
+ secretWord
+ '"'
)
gameIsDone = True
# Ask the player if they want to play again (but only if the game is done).
if gameIsDone:
if playAgain():
missedLetters = ""
correctLetters = ""
gameIsDone = False
secretWord = getRandomWord(words)
else:
break
if _name_ == "_main_":
main()
How would you design unit tests for the functions in this game?
How would you design integration tests for the main in this game?
Python Type Hints are Turing Complete
Ori Roth
Grigore showed that Java generics are Turing complete by describing a
reduction from Turing machines to Java subtyping. We apply Grigore’s
algorithm to Python type hints and deduce that they are Turing complete.
In addition, we present an alternative reduction in which the Turing
machines are simulated in real time, resulting in significantly lower
compilation times. Our work is accompanied by a Python implementation of
both reductions that compiles Turing machines into Python subtyping
machines.
Subjects: Programming Languages (cs.PL)
Cite as: arXiv:2208.14755 [cs.PL]
(or arXiv:2208.14755v1 [cs.PL] for this version)
https://doi.org/10.48550/arXiv.2208.14755
https://arxiv.org/abs/2208.14755
https://news.ycombinator.com/item?id=32779296
Next: 12-Strings.html