def square(x):
# computes square of a number
return x*xSession 12
Topics Covered
- Optional Static Typing
- Organizing Python Projects
- Handling Dependencies
- Best Practices
Questions
Q: What is the difference between a docstring and a comment?
help(square)Help on function square in module __main__:
square(x)
def square(x):
"""computes square of a number
"""
return x*xhelp(square)Help on function square in module __main__:
square(x)
computes square of a number
Comments are ignored by Python. Docstrings are attached to the function/module/class.
square.__doc__'computes square of a number\n '
sq = squarex = 10
y = 20x + y30
x.__add__(y)30
Refactoring
%%file split.py
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument("filename", help="Path to the file")
parser.add_argument("lines", type=int, help="Number of lines per smaller file")
args = parser.parse_args()
input_filename = args.filename
lines_per_file = args.
def get_filename(part_number):
base_filename = os.path.splitext(input_filename)[0]
return f'{base_filename}-part{part_number}.txt'
def write_file(filename, lines):
with open(filename, 'w') as f:
f.writelines(lines)
def splitlines(lines, n):
# TODO
pass
lines = open(input_filename).readlines()
part_number = 1
for chunk in splitlines(lines, lines_per_file):
filename = get_filename(part_number)
write_file(filename, chunk)
part_number += 1
# with open(input_filename, 'r') as input_file:
# file_count = 0
# lines = []
# for line in input_file:
# lines.append(line)
# if len(lines) >= lines_per_file:
# file_count += 1
# output_filename = get_filename(file_count)
# write_file(output_filename, lines)
# lines = []
# if lines:
# file_count += 1
# output_filename = get_filename(file_count)
# write_file(output_filename, lines)Overwriting split.py
Type Annotations
def square(n: int) -> int:
return n*n%%file sq.py
import sys
def square(n: int) -> int:
return n*n
if __name__ == "__main__":
n = sys.argv[1]
print(square(n))Overwriting sq.py
!python sq.py 5Traceback (most recent call last):
File "/home/jupyter-anand/book/sq.py", line 8, in <module>
print(square(n))
File "/home/jupyter-anand/book/sq.py", line 4, in square
return n*n
TypeError: can't multiply sequence by non-int of type 'str'
!mypy sq.pysq.py:7: error: Argument 1 to "square" has incompatible type "str"; expected "int" [arg-type]
Found 1 error in 1 file (checked 1 source file)
!pydoc sqHelp on module sq:
NAME
sq
FUNCTIONS
square(n: int) -> int
FILE
/home/jupyter-anand/book/sq.py
Declaring types for functions.
def add(x: float, y: float) -> float:
return x+yx: float = 5.0x5.0
def squares(numbers: list[int]) -> list[int]:
return [n*n for n in numbers]def read_hosts_file(filename: str) -> dict[str, str]:
"""Reads a file in /etc/hosts format and returns
a dictionary mapping from hostname to ip address.
"""
passfrom dataclasses import dataclass
@dataclass
class Point:
x: int
y: intdef closest_point(p: Point, points: list[Point]) -> Point:
"""Returns the closest point to p from the given points.
"""%load_problem type-annotations
Problem: Add Type Annotations
Add type annotations to all the functions in the code.py.
You can verify your solution using:
%verify_problem type-annotations
def square(n):
"""Computes square of an integer number.
>>> square(3)
9
"""
return n*n
def vector_add(v1, v2):
"""Adds two vectors.
>>> vector_add([1, 2, 3, 4], [10, 20, 30, 40])
[11, 22, 33, 44]
"""
return [a+b for a, b in zip(v1, v2)]
def mean(numbers):
"""Computes the mean of a list of numbers.
>>> mean([1.0, 2.0, 3.0, 4.0])
2.5
"""
return sum(numbers) / len(numbers)
def group(values, n):
"""
Takes a list of values and splits into smaller lists of given size.
>>> group([1, 2, 3, 4, 5, 6, 7, 8, 9], 3)
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> group([1, 2, 3, 4, 5, 6, 7, 8, 9], 4)
[[1, 2, 3, 4], [5, 6, 7, 8], [9]]
"""
return [values[i:i+n] for i in range(0, len(values), n)]
Structured Pattern Matching
commands = [
"deposit 50",
"withdraw 5",
"show-balance",
"withdraw 5",
"show-balance",
]balance = 0for cmd in commands:
match cmd.split():
case ["deposit", amount]:
balance += int(amount)
case ["withdraw", amount]:
balance -= int(amount)
case ["show-balance"]:
print("balance is", balance)
case _:
print("Invalid command")balance is 45
balance is 40
Example: Exploring github API
url = "https://api.github.com/users/simonw/repos"import requestsresult = requests.get(url).json()# result[0]def process_repo(data):
match data:
case {
"full_name": full_name,
"owner": {
"login": owner
},
"language": lang
}:
print(owner, full_name, lang)for repo in result:
process_repo(repo)simonw simonw/.github None
simonw simonw/2018.djangocon.us HTML
simonw simonw/2022.djangocon.us None
simonw simonw/24ways-datasette Jupyter Notebook
simonw simonw/act None
simonw simonw/action-transcription Python
simonw simonw/action-transcription-demo Python
simonw simonw/action-transcription-prototype Python
simonw simonw/advent-of-code-2022-in-rust Rust
simonw simonw/aiosqlite Python
simonw simonw/airtable-export Python
simonw simonw/ajquery.js None
simonw simonw/annotating_proxy Python
simonw simonw/apib2swagger JavaScript
simonw simonw/apio_django None
simonw simonw/archive-program None
simonw simonw/asgi-auth-github Python
simonw simonw/asgi-cors Python
simonw simonw/asgi-csrf Python
simonw simonw/asgi-debug Python
simonw simonw/asgi-gzip Python
simonw simonw/asgi-log-to-sqlite Python
simonw simonw/asgi-proxy-lib Python
simonw simonw/asgi-replay Python
simonw simonw/asgi-scope Python
simonw simonw/asgiref Python
simonw simonw/assume-aws-role-action None
simonw simonw/asyncinject Python
simonw simonw/awesome-asgi None
simonw simonw/awesome-db-tools None
Another example:
@dataclass
class Point:
x: float
y: float
@dataclass
class Circle:
center: Point
radius: float
@dataclass
class Rectangle:
center: Point
width: float
height: float
Shape = Circle | Rectangledef show(shape: Shape):
match shape:
case Circle(Point(x, y), r):
print(f"Circle with center ({x}, {y}) and radius {r}")
case Rectangle(Point(x, y), w, h):
print(f"Rectangle with center ({x}, {y}) and size {w}x{h}")
case _:
print("Invalid shape")show(Circle(Point(10, 10), 50))Circle with center (10, 10) and radius 50
show(Rectangle(Point(10, 10), 50, 100))Rectangle with center (10, 10) and size 50x100
Organizing Python Code
https://notes.pipal.in/notes/organizing-python-code/