Compare commits

..

60 Commits

Author SHA1 Message Date
David Beazley
a55856bf89 Merge pull request #91 from mz0/PEP-667
fix ValueError in f_locals.pop('self') Python 3.13+
2025-12-22 12:14:42 -06:00
David Beazley
b63b7f6da1 Merge pull request #92 from mz0/typo6.4
typo: name way -> same way
2025-12-22 12:06:17 -06:00
David Beazley
510182cb39 Merge pull request #87 from pathcl/fix/reference-soln1-1
add reference for solution 1-1
2025-12-22 12:05:38 -06:00
David Beazley
7c771bd014 Fixed Issue #93 2025-12-22 12:02:43 -06:00
Mark Zhitomirski
2d7dfa6718 typo: name way -> same way 2025-11-02 13:25:08 +04:00
Mark Zhitomirski
0cfde115ff fix ValueError in f_locals.pop('self') Python 3.13+
The error
ValueError: cannot remove local variables from FrameLocalsProxy

is caused by PEP 667 – Consistent views of namespaces
peps.python.org/pep-0667
implemented in Python 3.13
2025-10-31 00:13:49 +04:00
David Beazley
bc3b595cc3 Merge pull request #90 from mz0/fix-import-abc
fix AttributeError: module 'collections' has no attribute 'abc'
2025-10-22 14:48:39 -05:00
Mark Zhitomirski
1dd925e5b3 fix AttributeError: module 'collections' has no attribute 'abc' 2025-10-20 13:11:02 +04:00
Luis San Martin
9e290fd1a8 add reference for solution 2024-08-10 17:48:10 +00:00
David Beazley
dcf5e16d1f Minor edits 2024-08-02 08:10:00 -05:00
David Beazley
97794ae225 Added note about modernization 2024-07-31 14:43:12 -05:00
David Beazley
8471cb3a2f Added note about compatibility 2024-07-31 14:28:16 -05:00
David Beazley
3986af80de Updated slides with bugfixes 2024-07-31 11:27:48 -05:00
David Beazley
75763875df Merge branch 'main' of https://github.com/dabeaz-course/python-mastery into main 2024-07-31 11:11:16 -05:00
David Beazley
aab6f17470 Added links 2024-07-31 11:11:08 -05:00
David Beazley
8990494ab4 Merge pull request #41 from juliomorero/fix-ex5
Fix 5_1 and 5_3
2024-07-31 10:43:11 -05:00
David Beazley
1f6f5566eb Merge pull request #47 from darshandzend/main-2
Fix broken link
2024-07-31 10:40:59 -05:00
David Beazley
f2aebe0398 Merge pull request #54 from liangpeili/main
keep it consistent with solution in 1_4
2024-07-31 10:40:26 -05:00
David Beazley
1c5c97df36 Merge pull request #63 from Poor4ever/main
Fix duplicate input in ex2_5.md
2024-07-31 10:39:26 -05:00
David Beazley
a8e0892301 Merge pull request #66 from jarlethorsen/patch-1
Update ex5_6.md to fix NameError in example code
2024-07-31 10:37:12 -05:00
David Beazley
110101705e Merge pull request #71 from Curiosit/patch-3
Update formatter.py
2024-07-31 10:36:32 -05:00
David Beazley
6c742ccf84 Merge pull request #72 from jarlethorsen/patch-2
Update ex6_2.md to fix variable mismatch
2024-07-31 10:36:09 -05:00
David Beazley
7a8f6dec0e Merge pull request #82 from Se3ek/typo-correction
typo in ex2_2
2024-07-31 10:35:08 -05:00
David Beazley
2637086c55 Merge pull request #85 from galleon/patch-1
Update ex3_1.md
2024-07-31 10:34:22 -05:00
David Beazley
a053fa120a Added solutions for ex2.2 2024-07-31 10:31:35 -05:00
David Beazley
b865f86b33 Fixed typo in function name 2024-07-31 10:26:21 -05:00
David Beazley
94e9fdbf52 Added missing reading reference 2024-07-31 10:23:25 -05:00
David Beazley
fffcb971e6 Merge pull request #65 from Curiosit/main
Update ex7_1.md
2024-07-31 10:20:39 -05:00
David Beazley
85c03ffd79 added links to earlier exercises 2024-07-31 10:11:16 -05:00
Guillaume Alleon
48afeb56b5 Update ex3_1.md
fix a small typo
2024-06-15 15:26:05 +02:00
Seb
271ed03ff2 typo in ex2_5 2024-02-16 23:35:02 +01:00
Seb
0eedffd429 typo in ex2_2 2023-11-19 12:40:15 +01:00
Jarle Thorsen
92d7dc0f93 Update ex6_2.md to fix variable mismatch
The sell() method takes the nshares argument, however inside the method the variable shares is used instead.

This patch changes the name of the argument according to the variable used within the method.
2023-10-30 14:30:21 +01:00
MateuszMazurek
8111013443 Update formatter.py 2023-10-29 12:09:09 +01:00
Jarle Thorsen
1d20aaeca8 Update ex5_6.md to fix NameError in example code
Calling Stock() directly without providing the name of the module will result in the following error:

NameError: name 'Stock' is not defined

This fixes the bug in the example code.
2023-10-23 12:27:05 +02:00
Curiosit
3375d28b4d Update ex7_1.md
Fixed a typo: 6.6 -> 6.5
2023-10-22 23:06:47 +02:00
Poor4ever
73023e88a1 Fix duplicate input in ex2_5.md 2023-09-28 18:43:10 +08:00
Peili Liang
374965dbfb fix typo in ex2_2.md 2023-09-11 10:17:26 +08:00
Peili Liang
a6dd2238a2 keep it consistent with solution in 1_4 2023-09-08 09:24:52 +08:00
Darshan Zend
e414b66f4f Fix broken link
I think it's meant to be 6_5, unless there's a 6_6 that is missing altogether.
2023-08-18 18:29:56 +01:00
David Beazley
afec76dd94 Merge pull request #44 from darshandzend/main-1
typo
2023-08-14 10:02:06 -05:00
Darshan Zend
1e2916e64f typo 2023-08-14 15:47:31 +01:00
Julio Morero
56dfd08cd6 Fix 5_1 and 5_3 2023-08-07 14:14:43 -03:00
David Beazley
3ac425a715 Merge pull request #39 from Aymane11/main-1
Fix missing bracket in ex3_6.   Good catch!
2023-08-06 19:46:06 -05:00
Aymane Boumaaza
ccfcd4cb9f Fix missing bracket in ex3_6 2023-08-06 22:45:17 +01:00
David Beazley
d540e77118 Merge pull request #33 from darshandzend/patch-1
Fix typo
2023-07-28 19:58:50 -05:00
Darshan Zend
397b736762 Fix typo 2023-07-28 15:44:27 +01:00
David Beazley
9bb142586b Added question 2023-07-27 05:10:23 -05:00
David Beazley
558ece5cf5 Merge pull request #31 from davidlowryduda/patch-1
Update ex7_1.md
2023-07-26 19:52:09 -05:00
David Lowry-Duda
b82efeca2a Update ex7_1.md
This **tiny** commit corrects two typos.
2023-07-26 14:44:31 -04:00
David Beazley
09c35c10df Merge pull request #29 from l0b0/fix/Sequence
fix: Correct reference to `Sequence`
2023-07-25 18:43:56 -05:00
Victor Engmark
c079eb9507 fix: Correct reference to Sequence 2023-07-26 11:23:28 +12:00
David Beazley
393db776e1 Merge pull request #28 from SulimanSagindykov/patch-1
Update ex2_3.md
2023-07-23 04:41:06 -05:00
Suliman Sagindykov
48df268fa9 Update ex2_3.md
unnecessary space after a tab (from 5 to 4 spaces)
2023-07-21 16:19:24 +05:00
David Beazley
ac260673ae Merge pull request #16 from regisb/patch-1
docs: "what" -> "why" typo
2023-07-20 15:49:45 -05:00
Régis Behmo
85987ca6f1 docs: "what" -> "why" typo 2023-07-20 15:39:49 +02:00
David Beazley
13df3ab71a Merge pull request #14 from kozistr/fix/indentation
Fix indentation in exercise 9_4
2023-07-20 05:39:28 -05:00
David Beazley
fab0426db6 Merge pull request #13 from williamrowell/ex1_1
Fixed mixed indentation in exercise 1_1 and solution.
2023-07-20 05:38:56 -05:00
kozistr
e92c1811db fix: indentation 2023-07-20 15:32:48 +09:00
William Rowell
87f932a66b Fixed mixed indentation in exercise 1_1 and solution. 2023-07-19 23:20:45 -07:00
30 changed files with 96 additions and 57 deletions

View File

@@ -39,7 +39,7 @@ chars = '\|/'
def draw(rows, columns): def draw(rows, columns):
for r in rows: for r in rows:
print(''.join(random.choice(chars) for _ in range(columns))) print(''.join(random.choice(chars) for _ in range(columns)))
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) != 3: if len(sys.argv) != 3:

View File

@@ -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 automatically initializes elements for you--allowing an insertion of a
new element and an `append()` operation to be combined together. 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 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 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 It would be a shame to do all of that work and then do nothing with
the data. 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: following three questions:
1. How many bus routes exist in Chicago? 1. How many bus routes exist in Chicago?

View File

@@ -220,7 +220,7 @@ Watch what happens if you do the for-loop again:
```python ```python
>>> for n in squares: >>> 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: separated values:
```python ```python

View File

@@ -60,7 +60,6 @@ and adding a few more values to it:
```python ```python
>>> row = { 'route': '22', 'date': '01/01/2001', 'daytype': 'U', 'rides': 7354 } >>> row = { 'route': '22', 'date': '01/01/2001', 'daytype': 'U', 'rides': 7354 }
>>> sys.getsizeof(row) >>> sys.getsizeof(row)
>>> sys.getsizeof(row)
240 240
>>> row['a'] = 1 >>> row['a'] = 1
>>> sys.getsizeof(row) >>> sys.getsizeof(row)
@@ -175,7 +174,7 @@ function.
import collections import collections
... ...
class RideData(collections.Sequence): class RideData(collections.abc.Sequence):
def __init__(self): def __init__(self):
self.routes = [] # Columns self.routes = [] # Columns
self.dates = [] self.dates = []
@@ -204,9 +203,9 @@ into 4 separate `append()` operations.
# readrides.py # readrides.py
... ...
class RideData(collections.Sequence): class RideData(collections.abc.Sequence):
def __init__(self): 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.routes = []
self.dates = [] self.dates = []
self.daytypes = [] 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: looks like a list of dictionaries? For example, like this:
```python ```python
>>> rows = readrides.read_rides_as_columns('Data/ctabus.csv') >>> rows = readrides.read_rides_as_dicts('Data/ctabus.csv')
>>> rows >>> rows
<readrides.RideData object at 0x10f5054a8> <readrides.RideData object at 0x10f5054a8>
>>> len(rows) >>> len(rows)

View File

@@ -142,7 +142,8 @@ Or, if you wanted to read the CTA data:
## (c) Memory Revisited ## (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 ```python
>>> routes = { row['route'] for row in rows } >>> routes = { row['route'] for row in rows }

View File

@@ -55,7 +55,7 @@ definition?
## (c) Printing a Table ## (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: table. For example:
```python ```python

View File

@@ -146,7 +146,7 @@ Try it out:
>>> from tableformat import create_formatter >>> from tableformat import create_formatter
>>> formatter = create_formatter('text') >>> formatter = create_formatter('text')
>>> with redirect_stdout(open('out.txt', 'w')) as file: >>> 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() file.close()
>>> # Inspect the file >>> # Inspect the file

View File

@@ -115,7 +115,7 @@ kinds of input sources. For example:
```python ```python
>>> import gzip >>> import gzip
>>> import stock >>> 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 = reader.csv_as_instances(file, stock.Stock)
>>> port >>> port
[Stock('AA', 100, 32.2), Stock('IBM', 50, 91.1), Stock('CAT', 150, 83.44), [Stock('AA', 100, 32.2), Stock('IBM', 50, 91.1), Stock('CAT', 150, 83.44),

View File

@@ -25,7 +25,7 @@ import stock
class TestStock(unittest.TestCase): class TestStock(unittest.TestCase):
def test_create(self): 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.name, 'GOOG')
self.assertEqual(s.shares, 100) self.assertEqual(s.shares, 100)
self.assertEqual(s.price, 490.1) self.assertEqual(s.price, 490.1)

View File

@@ -9,7 +9,7 @@
*Files modified:* `structure.py`, `stock.py` *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: data structures. For example:
```python ```python
@@ -61,8 +61,9 @@ and class definitions:
```python ```python
>>> def _init(locs): >>> def _init(locs):
self = locs.pop('self') self = locs['self']
for name, val in locs.items(): for name, val in locs.items():
if name == 'self': continue
setattr(self, name, val) setattr(self, name, val)
>>> class Stock: >>> class Stock:
@@ -96,8 +97,9 @@ frame hacking. Try this variant of the `_init()` function:
>>> import sys >>> import sys
>>> def _init(): >>> def _init():
locs = sys._getframe(1).f_locals # Get callers local variables locs = sys._getframe(1).f_locals # Get callers local variables
self = locs.pop('self') self = locs['self']
for name, val in locs.items(): for name, val in locs.items():
if name == 'self': continue
setattr(self, name, val) setattr(self, name, val)
>>> >>>
``` ```
@@ -135,8 +137,9 @@ class Structure:
@staticmethod @staticmethod
def _init(): def _init():
locs = sys._getframe(1).f_locals locs = sys._getframe(1).f_locals
self = locs.pop('self') self = locs['self']
for name, val in locs.items(): for name, val in locs.items():
if name == 'self': continue
setattr(self, name, val) setattr(self, name, val)
... ...
``` ```
@@ -160,7 +163,7 @@ class Stock(Structure):
def cost(self): def cost(self):
return self.shares * self.price return self.shares * self.price
def sell(self, nshares): def sell(self, shares):
self.shares -= shares self.shares -= shares
``` ```

View File

@@ -84,7 +84,7 @@ class Stock(Structure):
Stock.create_init() 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 ```python
>>> s = Stock(name='GOOG', shares=100, price=490.1) >>> s = Stock(name='GOOG', shares=100, price=490.1)

View File

@@ -4,11 +4,11 @@
*Objectives:* *Objectives:*
- Learn how to define a simple decorator functions. - Learn how to define simple decorator functions.
*Files Created:* `logcall.py` *Files Created:* `logcall.py`
*Files Modifie:* `validate.py` *Files Modified:* `validate.py`
## (a) Your First Decorator ## (a) Your First Decorator
@@ -62,7 +62,7 @@ Calling sub
## (b) A Real Decorator ## (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`. enforced type annotations. Rewrite this class as a decorator function called `validated`.
It should allow you to write code like this: 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 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. 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) \] \[ [Solution](soln7_1.md) | [Index](index.md) | [Exercise 6.5](ex6_5.md) | [Exercise 7.2](ex7_2.md) \]

View File

@@ -165,8 +165,7 @@ a Python reserved word so you have to pick a slightly different name.
**Discussion** **Discussion**
Writing robust decorators is often a lot harder than it looks. 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) \] \[ [Solution](soln7_2.md) | [Index](index.md) | [Exercise 7.1](ex7_1.md) | [Exercise 7.3](ex7_3.md) \]

View File

@@ -41,7 +41,7 @@ def create_formatter(name, column_formats=None, upper_headers=False):
if column_formats: if column_formats:
class formatter_cls(ColumnFormatMixin, formatter_cls): class formatter_cls(ColumnFormatMixin, formatter_cls):
formats = column_formats formats = column_formats
if upper_headers: if upper_headers:
class formatter_cls(UpperHeadersMixin, formatter_cls): class formatter_cls(UpperHeadersMixin, formatter_cls):
@@ -139,7 +139,7 @@ def create_formatter(name, column_formats=None, upper_headers=False):
if column_formats: if column_formats:
class formatter_cls(ColumnFormatMixin, formatter_cls): class formatter_cls(ColumnFormatMixin, formatter_cls):
formats = column_formats formats = column_formats
if upper_headers: if upper_headers:
class formatter_cls(UpperHeadersMixin, formatter_cls): class formatter_cls(UpperHeadersMixin, formatter_cls):

View File

@@ -1,6 +1,4 @@
# Exercise 1.1 - Solution # Exercise 1.1 - Solution
Nothing here. Just follow along with the exercise. Check [here](../Solutions/1_1/art.py)
[Back](ex1_1.md)

View File

@@ -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 example, dictionaries of sets, nested dictionaries, etc. You might
need to do this to answer questions 3 and 4. 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) [Back](ex2_2.md)

View File

@@ -93,7 +93,7 @@ def read_rides_as_columns(filename):
# The great "fake" # The great "fake"
import collections import collections
class RideData(collections.Sequence): class RideData(collections.abc.Sequence):
def __init__(self): def __init__(self):
# Each value is a list with all of the values (a column) # Each value is a list with all of the values (a column)
self.routes = [] self.routes = []

View File

@@ -48,11 +48,10 @@ def read_csv_as_instances(filename, cls, *, headers=None):
import csv import csv
def convert_csv(lines, converter, *, headers=None): def convert_csv(lines, converter, *, headers=None):
records = []
rows = csv.reader(lines) rows = csv.reader(lines)
if headers is None: if headers is None:
headers = next(rows) headers = next(rows)
return map(lambda row: converter(headers, row), rows) return list(map(lambda row: converter(headers, row), rows))
``` ```

View File

@@ -11,8 +11,9 @@ class Structure:
@staticmethod @staticmethod
def _init(): def _init():
locs = sys._getframe(1).f_locals locs = sys._getframe(1).f_locals
self = locs.pop('self') self = locs['self']
for name, val in locs.items(): for name, val in locs.items():
if name == 'self': continue
setattr(self, name, val) setattr(self, name, val)
def __setattr__(self, name, value): def __setattr__(self, name, value):

View File

@@ -12,8 +12,9 @@ class Structure:
@staticmethod @staticmethod
def _init(): def _init():
locs = sys._getframe(1).f_locals locs = sys._getframe(1).f_locals
self = locs.pop('self') self = locs['self']
for name, val in locs.items(): for name, val in locs.items():
if name == 'self': continue
setattr(self, name, val) setattr(self, name, val)
def __setattr__(self, name, value): def __setattr__(self, name, value):

Binary file not shown.

View File

@@ -1,25 +1,33 @@
# Advanced Python Mastery # Advanced Python Mastery
A course by David Beazley (https://www.dabeaz.com) A course by David Beazley (https://www.dabeaz.com)
Copyright (C) 2007-2023 Copyright (C) 2007-2024
## Synopsis ## Synopsis
An exercise-driven course on Advanced Python Programming that was An exercise-driven course on Advanced Python Programming that was
battle-tested several hundred times on the corporate-training circuit battle-tested several hundred times on the corporate-training circuit
for more than a decade. Written by David Beazley, author of the 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 (Addison-Wesley). Released under a Creative Commons license. Free of
ads, tracking, pop-ups, newsletters, and AI. 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 ## Target Audience
This course is for Python programmers who want to move beyond This course is for Python programmers who want to move beyond
short scripts to writing more sophisticated programs. Topics short scripts to writing more sophisticated programs. To do that,
focus on programming techniques that get used in popular libraries and it helps to better understand the programming techniques used
frameworks. The primary goal is to better understand the Python language in popular libraries and frameworks. Thus, this course is mainly
itself so that you can understand other people's code and so that you for programmers who want to build a more complete mental model of the
can apply your newfound knowledge to your own projects. Python language itself and how it works. Ultimately, the goal
is to be able to apply this knowledge to your own projects.
## Prerequisites ## Prerequisites
@@ -94,7 +102,7 @@ exercises.
**A:** You can use [GitHub discussions](https://github.com/dabeaz-course/python-mastery/discussions) to discuss the course. **A:** You can use [GitHub discussions](https://github.com/dabeaz-course/python-mastery/discussions) to discuss the course.
**Q: What wasn't topic/tool/library X covered?** **Q: Why wasn't topic/tool/library X covered?**
**A:** The course was designed to be completed in an intense 4-day **A:** The course was designed to be completed in an intense 4-day
in-person format. It simply isn't possible to cover absolutely in-person format. It simply isn't possible to cover absolutely
@@ -106,9 +114,24 @@ Python language, not third party libraries or tooling.
**A:** Mainly, it's an issue of calendar timing and scope. Course **A:** Mainly, it's an issue of calendar timing and scope. Course
material was primarily developed pre-pandemic and represents Python as material was primarily developed pre-pandemic and represents Python as
it was at that time. Some topics (e.g., typing or async) are 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. 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?** **Q: How can I help?**
**A:** If you like the course, the best way to support it is to tell **A:** If you like the course, the best way to support it is to tell

View File

@@ -7,7 +7,7 @@ chars = '\|/'
def draw(rows, columns): def draw(rows, columns):
for r in range(rows): for r in range(rows):
print(''.join(random.choice(chars) for _ in range(columns))) print(''.join(random.choice(chars) for _ in range(columns)))
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) != 3: if len(sys.argv) != 3:

View File

@@ -12,7 +12,7 @@ def portfolio_cost(filename):
# This catches errors in int() and float() conversions above # This catches errors in int() and float() conversions above
except ValueError as e: except ValueError as e:
print("Couldn't parse:", line) print("Couldn't parse:", repr(line))
print("Reason:", e) print("Reason:", e)
return total_cost return total_cost

View File

@@ -1,6 +1,7 @@
# readrides.py # readrides.py
import csv import csv
import collections.abc
def read_rides_as_tuples(filename): def read_rides_as_tuples(filename):
''' '''
@@ -88,7 +89,7 @@ def read_rides_as_columns(filename):
# The great "fake" # The great "fake"
import collections import collections
class RideData(collections.Sequence): class RideData(collections.abc.Sequence):
def __init__(self): def __init__(self):
# Each value is a list with all of the values (a column) # Each value is a list with all of the values (a column)
self.routes = [] self.routes = []

View File

@@ -1,9 +1,10 @@
# colreader.py # colreader.py
import collections import collections
import collections.abc
import csv import csv
class DataCollection(collections.Sequence): class DataCollection(collections.abc.Sequence):
def __init__(self, columns): def __init__(self, columns):
self.column_names = list(columns) self.column_names = list(columns)
self.column_data = list(columns.values()) self.column_data = list(columns.values())
@@ -34,4 +35,3 @@ if __name__ == '__main__':
tracemalloc.start() tracemalloc.start()
data = read_csv_as_columns('../../Data/ctabus.csv', [intern, intern, intern, int]) data = read_csv_as_columns('../../Data/ctabus.csv', [intern, intern, intern, int])
print(tracemalloc.get_traced_memory()) print(tracemalloc.get_traced_memory())

View File

@@ -9,12 +9,15 @@ def convert_csv(lines, converter, *, headers=None):
return list(map(lambda row: converter(headers, row), rows)) return list(map(lambda row: converter(headers, row), rows))
def csv_as_dicts(lines, types, *, headers=None): def csv_as_dicts(lines, types, *, headers=None):
return convert_csv(lines, return convert_csv(lines,
lambda headers, row: { name: func(val) for name, func, val in zip(headers, types, row) }) 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): def csv_as_instances(lines, cls, *, headers=None):
return convert_csv(lines, 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): def read_csv_as_dicts(filename, types, *, headers=None):
''' '''

View File

@@ -8,8 +8,9 @@ class Structure:
@staticmethod @staticmethod
def _init(): def _init():
locs = sys._getframe(1).f_locals locs = sys._getframe(1).f_locals
self = locs.pop('self') self = locs['self']
for name, val in locs.items(): for name, val in locs.items():
if name == 'self': continue
setattr(self, name, val) setattr(self, name, val)
def __setattr__(self, name, value): def __setattr__(self, name, value):

View File

@@ -9,8 +9,9 @@ class Structure:
@staticmethod @staticmethod
def _init(): def _init():
locs = sys._getframe(1).f_locals locs = sys._getframe(1).f_locals
self = locs.pop('self') self = locs['self']
for name, val in locs.items(): for name, val in locs.items():
if name == 'self': continue
setattr(self, name, val) setattr(self, name, val)
def __setattr__(self, name, value): def __setattr__(self, name, value):

View File

@@ -1,4 +1,4 @@
# tableformat.py # formatter.py
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
def print_table(records, fields, formatter): def print_table(records, fields, formatter):