From f8171948655a9dcf94e9311084ea245004a399ea Mon Sep 17 00:00:00 2001 From: zzl0 Date: Sat, 26 Dec 2020 23:51:54 -0500 Subject: [PATCH] my notes --- Notes/MyNote.md | 169 +++++++++++++++++++++++++++++++++++++++ Solutions/3_18/report.py | 4 +- Work/bounce.py | 6 ++ Work/mortgage.py | 25 ++++++ Work/sears.py | 15 ++++ Work/stock.py | 11 +++ 6 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 Notes/MyNote.md create mode 100644 Work/sears.py create mode 100644 Work/stock.py diff --git a/Notes/MyNote.md b/Notes/MyNote.md new file mode 100644 index 000000000..ba8e2beac --- /dev/null +++ b/Notes/MyNote.md @@ -0,0 +1,169 @@ + +# 3.1 Scripting + +> Also, a little known fact is that Python runs a bit faster if you use functions. + +https://stackoverflow.com/questions/11241523/why-does-python-code-run-faster-in-a-function + +The short answer is that it is faster to store local variables than globals. + +# 3.6 Design Discussion + +In this section we reconsider a design decision made earlier. + +### Filenames versus Iterables + +Compare these two programs that return the same output. + +```python +# Provide a filename +def read_data(filename): + records = [] + with open(filename) as f: + for line in f: + ... + records.append(r) + return records + +d = read_data('file.csv') +``` + +```python +# Provide lines +def read_data(lines): + records = [] + for line in lines: + ... + records.append(r) + return records + +with open('file.csv') as f: + d = read_data(f) +``` + +* Which of these functions do you prefer? Why? +* Which of these functions is more flexible? + +### Deep Idea: "Duck Typing" + +[Duck Typing](https://en.wikipedia.org/wiki/Duck_typing) is a computer +programming concept to determine whether an object can be used for a +particular purpose. It is an application of the [duck +test](https://en.wikipedia.org/wiki/Duck_test). + +> If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck. + +In the second version of `read_data()` above, the function expects any +iterable object. Not just the lines of a file. + +```python +def read_data(lines): + records = [] + for line in lines: + ... + records.append(r) + return records +``` + +This means that we can use it with other *lines*. + +```python +# A CSV file +lines = open('data.csv') +data = read_data(lines) + +# A zipped file +lines = gzip.open('data.csv.gz','rt') +data = read_data(lines) + +# The Standard Input +lines = sys.stdin +data = read_data(lines) + +# A list of strings +lines = ['ACME,50,91.1','IBM,75,123.45', ... ] +data = read_data(lines) +``` + +There is considerable flexibility with this design. + +*Question: Should we embrace or fight this flexibility?* + +### Library Design Best Practices + +Code libraries are often better served by embracing flexibility. +Don't restrict your options. With great flexibility comes great power. + +# 5.1 Dictionaries Revisited + +### The "Mixin" Pattern + +The *Mixin* pattern is a class with a fragment of code. + +```python +class Loud: + def noise(self): + return super().noise().upper() +``` + +This class is not usable in isolation. +It mixes with other classes via inheritance. + +```python +class LoudDog(Loud, Dog): + pass + +class LoudBike(Loud, Bike): + pass +``` + +Miraculously, loudness was now implemented just once and reused +in two completely unrelated classes. This sort of trick is one +of the primary uses of multiple inheritance in Python. + +### Why `super()` + +Always use `super()` when overriding methods. + +```python +class Loud: + def noise(self): + return super().noise().upper() +``` + +`super()` delegates to the *next class* on the MRO. + +The tricky bit is that you don't know what it is. You especially don't +know what it is if multiple inheritance is being used. + +### Some Cautions + +Multiple inheritance is a powerful tool. Remember that with power +comes responsibility. Frameworks / libraries sometimes use it for +advanced features involving composition of components. Now, forget +that you saw that. + + +# 6.1 Interation Protocol + +One important observation about this--generally code is considered +"Pythonic" if it speaks the common vocabulary of how other parts of +Python normally work. For container objects, supporting iteration, +indexing, containment, and other kinds of operators is an important +part of this. + + +# 6.4 More Generators + +### Why Generators + +* Many problems are much more clearly expressed in terms of iteration. + * Looping over a collection of items and performing some kind of operation (searching, replacing, modifying, etc.). + * Processing pipelines can be applied to a wide range of data processing problems. +* Better memory efficiency. + * Only produce values when needed. + * Contrast to constructing giant lists. + * Can operate on streaming data +* Generators encourage code reuse + * Separates the *iteration* from code that uses the iteration + * You can build a toolbox of interesting iteration functions and *mix-n-match*. diff --git a/Solutions/3_18/report.py b/Solutions/3_18/report.py index fbf71bd10..89b35e7a8 100644 --- a/Solutions/3_18/report.py +++ b/Solutions/3_18/report.py @@ -40,11 +40,11 @@ def print_report(reportdata): for row in reportdata: print('%10s %10d %10.2f %10.2f' % row) -def portfolio_report(portfoliofile, pricefile): +def portfolio_report(portfoliofile, pricefile): ''' Make a stock report given portfolio and price data files. ''' - # Read data files + # Read data files portfolio = read_portfolio(portfoliofile) prices = read_prices(pricefile) diff --git a/Work/bounce.py b/Work/bounce.py index 3660ddd82..c00f25716 100644 --- a/Work/bounce.py +++ b/Work/bounce.py @@ -1,3 +1,9 @@ # bounce.py # # Exercise 1.5 + + +height = 100 +for bounce in range(1, 11): + height *= 3 / 5 + print(bounce, round(height, 4)) diff --git a/Work/mortgage.py b/Work/mortgage.py index d527314e3..b82d117bb 100644 --- a/Work/mortgage.py +++ b/Work/mortgage.py @@ -1,3 +1,28 @@ # mortgage.py # # Exercise 1.7 + +principal = 500000.0 +rate = 0.05 +payment = 2684.11 +total_paid = 0.0 + +extra_payment_start_month = 61 +extra_payment_end_month = 108 +extra_payment = 1000 + +months = 0 +while principal > 0: + months += 1 + curr_payment = (payment + extra_payment) if extra_payment_start_month <= months <= extra_payment_end_month else payment + principal = principal * (1+rate/12) - curr_payment + + if principal < 0: + curr_payment += principal + principal = 0.0 + + total_paid = total_paid + curr_payment + print(f'{months} {total_paid:.2f} {principal:.2f}') + +print(f'Total paid {total_paid:.2f}') +print(f'Months {months}') diff --git a/Work/sears.py b/Work/sears.py new file mode 100644 index 000000000..df968fff7 --- /dev/null +++ b/Work/sears.py @@ -0,0 +1,15 @@ +# sears.py + +bill_thickness = 0.11 * 0.001 # Meters (0.11 mm) +sears_height = 442 # Height (meters) +num_bills = 1 +day = 1 + +while num_bills * bill_thickness < sears_height: + print(day, num_bills, num_bills * bill_thickness) + day = day + 1 + num_bills = num_bills * 2 + +print('Number of days', day) +print('Number of bills', num_bills) +print('Final height', num_bills * bill_thickness) diff --git a/Work/stock.py b/Work/stock.py new file mode 100644 index 000000000..1b4a2be15 --- /dev/null +++ b/Work/stock.py @@ -0,0 +1,11 @@ +class Stock: + def __init__(self, name, shares, price): + self.name = name + self.shares = shares + self.price = price + + def cost(self): + return self.shares * self.price + + def sell(self, shares): + self.shares -= shares