Compare commits
54 Commits
ac260673ae
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a55856bf89 | ||
|
|
b63b7f6da1 | ||
|
|
510182cb39 | ||
|
|
7c771bd014 | ||
|
|
2d7dfa6718 | ||
|
|
0cfde115ff | ||
|
|
bc3b595cc3 | ||
|
|
1dd925e5b3 | ||
|
|
9e290fd1a8 | ||
|
|
dcf5e16d1f | ||
|
|
97794ae225 | ||
|
|
8471cb3a2f | ||
|
|
3986af80de | ||
|
|
75763875df | ||
|
|
aab6f17470 | ||
|
|
8990494ab4 | ||
|
|
1f6f5566eb | ||
|
|
f2aebe0398 | ||
|
|
1c5c97df36 | ||
|
|
a8e0892301 | ||
|
|
110101705e | ||
|
|
6c742ccf84 | ||
|
|
7a8f6dec0e | ||
|
|
2637086c55 | ||
|
|
a053fa120a | ||
|
|
b865f86b33 | ||
|
|
94e9fdbf52 | ||
|
|
fffcb971e6 | ||
|
|
85c03ffd79 | ||
|
|
48afeb56b5 | ||
|
|
271ed03ff2 | ||
|
|
0eedffd429 | ||
|
|
92d7dc0f93 | ||
|
|
8111013443 | ||
|
|
1d20aaeca8 | ||
|
|
3375d28b4d | ||
|
|
73023e88a1 | ||
|
|
374965dbfb | ||
|
|
a6dd2238a2 | ||
|
|
e414b66f4f | ||
|
|
afec76dd94 | ||
|
|
1e2916e64f | ||
|
|
56dfd08cd6 | ||
|
|
3ac425a715 | ||
|
|
ccfcd4cb9f | ||
|
|
d540e77118 | ||
|
|
397b736762 | ||
|
|
9bb142586b | ||
|
|
558ece5cf5 | ||
|
|
b82efeca2a | ||
|
|
09c35c10df | ||
|
|
c079eb9507 | ||
|
|
393db776e1 | ||
|
|
48df268fa9 |
@@ -152,7 +152,7 @@ The key feature that makes this work is that a defaultdict
|
||||
automatically initializes elements for you--allowing an insertion of a
|
||||
new element and an `append()` operation to be combined together.
|
||||
|
||||
## (c) Data Analysis Challenge
|
||||
## (d) Data Analysis Challenge
|
||||
|
||||
In the last exercise you just wrote some code to read CSV-data related
|
||||
to the Chicago Transit Authority. For example, you can grab the data
|
||||
@@ -167,7 +167,7 @@ as dictionaries like this:
|
||||
It would be a shame to do all of that work and then do nothing with
|
||||
the data.
|
||||
|
||||
In this exercise, you task is this: write a program to answer the
|
||||
In this exercise, your task is this: write a program to answer the
|
||||
following three questions:
|
||||
|
||||
1. How many bus routes exist in Chicago?
|
||||
|
||||
@@ -220,7 +220,7 @@ Watch what happens if you do the for-loop again:
|
||||
|
||||
```python
|
||||
>>> for n in squares:
|
||||
print(n)
|
||||
print(n)
|
||||
|
||||
>>>
|
||||
```
|
||||
@@ -291,7 +291,7 @@ False
|
||||
>>>
|
||||
```
|
||||
|
||||
Here is an subtle use of a generator expression in making comma
|
||||
Here is a subtle use of a generator expression in making comma
|
||||
separated values:
|
||||
|
||||
```python
|
||||
|
||||
@@ -60,7 +60,6 @@ and adding a few more values to it:
|
||||
```python
|
||||
>>> row = { 'route': '22', 'date': '01/01/2001', 'daytype': 'U', 'rides': 7354 }
|
||||
>>> sys.getsizeof(row)
|
||||
>>> sys.getsizeof(row)
|
||||
240
|
||||
>>> row['a'] = 1
|
||||
>>> sys.getsizeof(row)
|
||||
@@ -175,7 +174,7 @@ function.
|
||||
|
||||
import collections
|
||||
...
|
||||
class RideData(collections.Sequence):
|
||||
class RideData(collections.abc.Sequence):
|
||||
def __init__(self):
|
||||
self.routes = [] # Columns
|
||||
self.dates = []
|
||||
@@ -204,9 +203,9 @@ into 4 separate `append()` operations.
|
||||
# readrides.py
|
||||
...
|
||||
|
||||
class RideData(collections.Sequence):
|
||||
class RideData(collections.abc.Sequence):
|
||||
def __init__(self):
|
||||
# Each value is a list with all of the values (a column)
|
||||
# Each value is a list with all the values (a column)
|
||||
self.routes = []
|
||||
self.dates = []
|
||||
self.daytypes = []
|
||||
@@ -297,7 +296,7 @@ the `RideData` class so that it produces a proper slice that
|
||||
looks like a list of dictionaries? For example, like this:
|
||||
|
||||
```python
|
||||
>>> rows = readrides.read_rides_as_columns('Data/ctabus.csv')
|
||||
>>> rows = readrides.read_rides_as_dicts('Data/ctabus.csv')
|
||||
>>> rows
|
||||
<readrides.RideData object at 0x10f5054a8>
|
||||
>>> len(rows)
|
||||
|
||||
@@ -142,7 +142,8 @@ Or, if you wanted to read the CTA data:
|
||||
|
||||
## (c) Memory Revisited
|
||||
|
||||
In the CTA bus data, we determined that there were 181 unique bus routes.
|
||||
In [Exercise 2.1](ex2_1.md) we explored memory use and in [Exercise 2.2](ex2_2.md), we
|
||||
determined that there were 181 unique bus routes in Chicago.
|
||||
|
||||
```python
|
||||
>>> routes = { row['route'] for row in rows }
|
||||
|
||||
@@ -55,7 +55,7 @@ definition?
|
||||
|
||||
## (c) Printing a Table
|
||||
|
||||
Table the data read in part (b) and use it to make a nicely formatted
|
||||
Take the data read in part (b) and use it to make a nicely formatted
|
||||
table. For example:
|
||||
|
||||
```python
|
||||
|
||||
@@ -146,7 +146,7 @@ Try it out:
|
||||
>>> from tableformat import create_formatter
|
||||
>>> formatter = create_formatter('text')
|
||||
>>> with redirect_stdout(open('out.txt', 'w')) as file:
|
||||
tableformat.print_table(portfolio, ['name','shares','price', formatter)
|
||||
tableformat.print_table(portfolio, ['name','shares','price'], formatter)
|
||||
file.close()
|
||||
|
||||
>>> # Inspect the file
|
||||
|
||||
@@ -115,7 +115,7 @@ kinds of input sources. For example:
|
||||
```python
|
||||
>>> import gzip
|
||||
>>> import stock
|
||||
>>> file = gzip.open('Data/portfolio.csv.gz')
|
||||
>>> file = gzip.open('Data/portfolio.csv.gz', 'rt')
|
||||
>>> port = reader.csv_as_instances(file, stock.Stock)
|
||||
>>> port
|
||||
[Stock('AA', 100, 32.2), Stock('IBM', 50, 91.1), Stock('CAT', 150, 83.44),
|
||||
|
||||
@@ -25,7 +25,7 @@ import stock
|
||||
|
||||
class TestStock(unittest.TestCase):
|
||||
def test_create(self):
|
||||
s = Stock('GOOG', 100, 490.1)
|
||||
s = stock.Stock('GOOG', 100, 490.1)
|
||||
self.assertEqual(s.name, 'GOOG')
|
||||
self.assertEqual(s.shares, 100)
|
||||
self.assertEqual(s.price, 490.1)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
*Files modified:* `structure.py`, `stock.py`
|
||||
|
||||
In the last exercise, you create a class `Structure` that made it easy to define
|
||||
In the last exercise, you created a class `Structure` that made it easy to define
|
||||
data structures. For example:
|
||||
|
||||
```python
|
||||
@@ -61,8 +61,9 @@ and class definitions:
|
||||
|
||||
```python
|
||||
>>> def _init(locs):
|
||||
self = locs.pop('self')
|
||||
self = locs['self']
|
||||
for name, val in locs.items():
|
||||
if name == 'self': continue
|
||||
setattr(self, name, val)
|
||||
|
||||
>>> class Stock:
|
||||
@@ -96,8 +97,9 @@ frame hacking. Try this variant of the `_init()` function:
|
||||
>>> import sys
|
||||
>>> def _init():
|
||||
locs = sys._getframe(1).f_locals # Get callers local variables
|
||||
self = locs.pop('self')
|
||||
self = locs['self']
|
||||
for name, val in locs.items():
|
||||
if name == 'self': continue
|
||||
setattr(self, name, val)
|
||||
>>>
|
||||
```
|
||||
@@ -135,8 +137,9 @@ class Structure:
|
||||
@staticmethod
|
||||
def _init():
|
||||
locs = sys._getframe(1).f_locals
|
||||
self = locs.pop('self')
|
||||
self = locs['self']
|
||||
for name, val in locs.items():
|
||||
if name == 'self': continue
|
||||
setattr(self, name, val)
|
||||
...
|
||||
```
|
||||
@@ -160,7 +163,7 @@ class Stock(Structure):
|
||||
def cost(self):
|
||||
return self.shares * self.price
|
||||
|
||||
def sell(self, nshares):
|
||||
def sell(self, shares):
|
||||
self.shares -= shares
|
||||
```
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ class Stock(Structure):
|
||||
Stock.create_init()
|
||||
```
|
||||
|
||||
The resulting class should work exactly the name way as before:
|
||||
The resulting class should work exactly the same way as before:
|
||||
|
||||
```python
|
||||
>>> s = Stock(name='GOOG', shares=100, price=490.1)
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
*Objectives:*
|
||||
|
||||
- Learn how to define a simple decorator functions.
|
||||
- Learn how to define simple decorator functions.
|
||||
|
||||
*Files Created:* `logcall.py`
|
||||
|
||||
*Files Modifie:* `validate.py`
|
||||
*Files Modified:* `validate.py`
|
||||
|
||||
## (a) Your First Decorator
|
||||
|
||||
@@ -62,7 +62,7 @@ Calling sub
|
||||
|
||||
## (b) A Real Decorator
|
||||
|
||||
In [Exercise 6.6](ex6_6.md), you created a callable class `ValidatedFunction` that
|
||||
In [Exercise 6.5](ex6_5.md), you created a callable class `ValidatedFunction` that
|
||||
enforced type annotations. Rewrite this class as a decorator function called `validated`.
|
||||
It should allow you to write code like this:
|
||||
|
||||
@@ -124,7 +124,7 @@ class Stock:
|
||||
```
|
||||
|
||||
Note: This part doesn't involve a lot of code, but there are a lot of low-level
|
||||
fiddly bits. The solution will look almost the same as for Exercise 6.6. Don't
|
||||
fiddly bits. The solution will look almost the same as for Exercise 6.5. Don't
|
||||
be shy about looking at solution code though.
|
||||
|
||||
\[ [Solution](soln7_1.md) | [Index](index.md) | [Exercise 6.5](ex6_5.md) | [Exercise 7.2](ex7_2.md) \]
|
||||
|
||||
@@ -165,8 +165,7 @@ a Python reserved word so you have to pick a slightly different name.
|
||||
**Discussion**
|
||||
|
||||
Writing robust decorators is often a lot harder than it looks.
|
||||
Recommended reading:
|
||||
|
||||
Recommended reading: [How you implemented your Python decorator is wrong](https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/01-how-you-implemented-your-python-decorator-is-wrong.md)
|
||||
|
||||
\[ [Solution](soln7_2.md) | [Index](index.md) | [Exercise 7.1](ex7_1.md) | [Exercise 7.3](ex7_3.md) \]
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# Exercise 1.1 - Solution
|
||||
|
||||
Nothing here. Just follow along with the exercise.
|
||||
Check [here](../Solutions/1_1/art.py)
|
||||
|
||||
|
||||
[Back](ex1_1.md)
|
||||
|
||||
@@ -18,6 +18,15 @@ maps the route name to the total ride count for that route. A `Counter` object
|
||||
example, dictionaries of sets, nested dictionaries, etc. You might
|
||||
need to do this to answer questions 3 and 4.
|
||||
|
||||
Even though no code is provided, here are some answers to the questions
|
||||
so that you can check your work:
|
||||
|
||||
1. How many bus routes exist in Chicago? (Answer: 181)
|
||||
|
||||
2. How many people rode the number 22 bus on February 2, 2011? (Answer: 5055)
|
||||
|
||||
3. What is the total number of rides taken on each bus route? (Answer: for the top three routes, [('79', 133796763), ('9', 117923787), ('49', 95915008)])
|
||||
|
||||
4. What five bus routes had the greatest ten-year increase in ridership from 2001 to 2011? (Answer: [('15', 2732209), ('147', 2107910), ('66', 1612958), ('12', 1612067), ('14', 1351308)])
|
||||
|
||||
[Back](ex2_2.md)
|
||||
|
||||
@@ -93,7 +93,7 @@ def read_rides_as_columns(filename):
|
||||
# The great "fake"
|
||||
|
||||
import collections
|
||||
class RideData(collections.Sequence):
|
||||
class RideData(collections.abc.Sequence):
|
||||
def __init__(self):
|
||||
# Each value is a list with all of the values (a column)
|
||||
self.routes = []
|
||||
|
||||
@@ -48,11 +48,10 @@ def read_csv_as_instances(filename, cls, *, headers=None):
|
||||
import csv
|
||||
|
||||
def convert_csv(lines, converter, *, headers=None):
|
||||
records = []
|
||||
rows = csv.reader(lines)
|
||||
if headers is None:
|
||||
headers = next(rows)
|
||||
return map(lambda row: converter(headers, row), rows)
|
||||
return list(map(lambda row: converter(headers, row), rows))
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@ class Structure:
|
||||
@staticmethod
|
||||
def _init():
|
||||
locs = sys._getframe(1).f_locals
|
||||
self = locs.pop('self')
|
||||
self = locs['self']
|
||||
for name, val in locs.items():
|
||||
if name == 'self': continue
|
||||
setattr(self, name, val)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
|
||||
@@ -12,8 +12,9 @@ class Structure:
|
||||
@staticmethod
|
||||
def _init():
|
||||
locs = sys._getframe(1).f_locals
|
||||
self = locs.pop('self')
|
||||
self = locs['self']
|
||||
for name, val in locs.items():
|
||||
if name == 'self': continue
|
||||
setattr(self, name, val)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
|
||||
Binary file not shown.
39
README.md
39
README.md
@@ -1,25 +1,33 @@
|
||||
# Advanced Python Mastery
|
||||
|
||||
A course by David Beazley (https://www.dabeaz.com)
|
||||
Copyright (C) 2007-2023
|
||||
Copyright (C) 2007-2024
|
||||
|
||||
## Synopsis
|
||||
|
||||
An exercise-driven course on Advanced Python Programming that was
|
||||
battle-tested several hundred times on the corporate-training circuit
|
||||
for more than a decade. Written by David Beazley, author of the
|
||||
Python Cookbook, 3rd Edition (O'Reilly) and Python Distilled
|
||||
[Python Cookbook, 3rd Edition](https://www.dabeaz.com/cookbook.html) (O'Reilly) and
|
||||
[Python Distilled](https://www.dabeaz.com/python-distilled/index.html)
|
||||
(Addison-Wesley). Released under a Creative Commons license. Free of
|
||||
ads, tracking, pop-ups, newsletters, and AI.
|
||||
|
||||
Everything in this course should work with the latest version of
|
||||
Python, but be aware that the course primarily targets the feature set
|
||||
of Python 3.6. As such, certain modern features don't get coverage.
|
||||
Honestly, this shouldn't affect you much unless you're trying to write code
|
||||
that's freakishly clever.
|
||||
|
||||
## Target Audience
|
||||
|
||||
This course is for Python programmers who want to move beyond
|
||||
short scripts to writing more sophisticated programs. Topics
|
||||
focus on programming techniques that get used in popular libraries and
|
||||
frameworks. The primary goal is to better understand the Python language
|
||||
itself so that you can understand other people's code and so that you
|
||||
can apply your newfound knowledge to your own projects.
|
||||
short scripts to writing more sophisticated programs. To do that,
|
||||
it helps to better understand the programming techniques used
|
||||
in popular libraries and frameworks. Thus, this course is mainly
|
||||
for programmers who want to build a more complete mental model of the
|
||||
Python language itself and how it works. Ultimately, the goal
|
||||
is to be able to apply this knowledge to your own projects.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -106,9 +114,24 @@ Python language, not third party libraries or tooling.
|
||||
**A:** Mainly, it's an issue of calendar timing and scope. Course
|
||||
material was primarily developed pre-pandemic and represents Python as
|
||||
it was at that time. Some topics (e.g., typing or async) are
|
||||
sufficiently complex that they would be bettered covered on their own
|
||||
sufficiently complex that they would be better covered on their own
|
||||
in a separate course.
|
||||
|
||||
**Q: Do you have plans to modernize the course?**
|
||||
|
||||
**A:** It is my intention that everything in the course apply to the
|
||||
latest version of Python. Unless Python makes backwards-incompatible
|
||||
changes to the core language, that should hold. Although the course
|
||||
doesn't cover every new features, I won't rule out future changes. A
|
||||
lot depends on my available time and interest however. So, I make no
|
||||
promises.
|
||||
|
||||
**Q: Why did you release the course?**
|
||||
|
||||
**A:** This course was extensively taught pre-pandemic. Post-pandemic,
|
||||
my teaching has shifted towards projects and CS fundamentals.
|
||||
However, why let a good course just languish on my computer?
|
||||
|
||||
**Q: How can I help?**
|
||||
|
||||
**A:** If you like the course, the best way to support it is to tell
|
||||
|
||||
@@ -12,7 +12,7 @@ def portfolio_cost(filename):
|
||||
|
||||
# This catches errors in int() and float() conversions above
|
||||
except ValueError as e:
|
||||
print("Couldn't parse:", line)
|
||||
print("Couldn't parse:", repr(line))
|
||||
print("Reason:", e)
|
||||
|
||||
return total_cost
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# readrides.py
|
||||
|
||||
import csv
|
||||
import collections.abc
|
||||
|
||||
def read_rides_as_tuples(filename):
|
||||
'''
|
||||
@@ -88,7 +89,7 @@ def read_rides_as_columns(filename):
|
||||
# The great "fake"
|
||||
|
||||
import collections
|
||||
class RideData(collections.Sequence):
|
||||
class RideData(collections.abc.Sequence):
|
||||
def __init__(self):
|
||||
# Each value is a list with all of the values (a column)
|
||||
self.routes = []
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# colreader.py
|
||||
|
||||
import collections
|
||||
import collections.abc
|
||||
import csv
|
||||
|
||||
class DataCollection(collections.Sequence):
|
||||
class DataCollection(collections.abc.Sequence):
|
||||
def __init__(self, columns):
|
||||
self.column_names = list(columns)
|
||||
self.column_data = list(columns.values())
|
||||
@@ -34,4 +35,3 @@ if __name__ == '__main__':
|
||||
tracemalloc.start()
|
||||
data = read_csv_as_columns('../../Data/ctabus.csv', [intern, intern, intern, int])
|
||||
print(tracemalloc.get_traced_memory())
|
||||
|
||||
|
||||
@@ -9,12 +9,15 @@ def convert_csv(lines, converter, *, headers=None):
|
||||
return list(map(lambda row: converter(headers, row), rows))
|
||||
|
||||
def csv_as_dicts(lines, types, *, headers=None):
|
||||
return convert_csv(lines,
|
||||
lambda headers, row: { name: func(val) for name, func, val in zip(headers, types, row) })
|
||||
return convert_csv(lines,
|
||||
lambda headers, row: {name: func(val) for name, func, val in zip(headers, types, row)},
|
||||
headers=headers)
|
||||
|
||||
|
||||
def csv_as_instances(lines, cls, *, headers=None):
|
||||
return convert_csv(lines,
|
||||
lambda headers, row: cls.from_row(row))
|
||||
lambda headers, row: cls.from_row(row),
|
||||
headers=headers)
|
||||
|
||||
def read_csv_as_dicts(filename, types, *, headers=None):
|
||||
'''
|
||||
|
||||
@@ -8,8 +8,9 @@ class Structure:
|
||||
@staticmethod
|
||||
def _init():
|
||||
locs = sys._getframe(1).f_locals
|
||||
self = locs.pop('self')
|
||||
self = locs['self']
|
||||
for name, val in locs.items():
|
||||
if name == 'self': continue
|
||||
setattr(self, name, val)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
|
||||
@@ -9,8 +9,9 @@ class Structure:
|
||||
@staticmethod
|
||||
def _init():
|
||||
locs = sys._getframe(1).f_locals
|
||||
self = locs.pop('self')
|
||||
self = locs['self']
|
||||
for name, val in locs.items():
|
||||
if name == 'self': continue
|
||||
setattr(self, name, val)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# tableformat.py
|
||||
# formatter.py
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
def print_table(records, fields, formatter):
|
||||
|
||||
Reference in New Issue
Block a user