# 3.1 Scripting In this part we look more closely at the practice of writing Python scripts. ### What is a Script? A *script* is a program that runs a series of statements and stops. ```python # program.py statement1 statement2 statement3 ... ``` We have been writing scripts to this point. ### A Problem If you write a useful script, it will grow in features and functionality. You may want to apply it to other related problems. Over time, it might become a critical application. And if you don't take care, it might turn into a huge tangled mess. So, let's get organized. ### Defining Things You must always define things before they get used later on in a program. ```python def square(x): return x*x a = 42 b = a + 2 # Requires that `a` is defined z = square(b) # Requires `square` and `b` to be defined ``` **The order is important.** You almost always put the definitions of variables an functions near the beginning. ### Defining Functions It is a good idea to put all of the code related to a single *task* all in one place. ```python def read_prices(filename): prices = {} with open(filename) as f: f_csv = csv.reader(f) for row in f_csv: prices[row[0]] = float(row[1]) return prices ``` A function also simplifies repeated operations. ```python oldprices = read_prices('oldprices.csv') newprices = read_prices('newprices.csv') ``` ### What is a Function? A function is a named sequence of statements. ```python def funcname(args): statement statement ... return result ``` *Any* Python statement can be used inside. ```python def foo(): import math print(math.sqrt(2)) help(math) ``` There are no *special* statements in Python. ### Function Definition Functions can be *defined* in any order. ```python def foo(x): bar(x) def bar(x): statements # OR def bar(x) statements def foo(x): bar(x) ``` Functions must only be defined before they are actually *used* (or called) during program execution. ```python foo(3) # foo must be defined already ``` Stylistically, it is probably more common to see functions defined in a *bottom-up* fashion. ### Bottom-up Style Functions are treated as building blocks. The smaller/simpler blocks go first. ```python # myprogram.py def foo(x): ... def bar(x): ... foo(x) # Defined above ... def spam(x): ... bar(x) # Defined above ... spam(42) # Code that uses the functions appears at the end ``` Later functions build upon earlier functions. ### Function Design Ideally, functions should be a *black box*. They should only operate on passed inputs and avoid global variables and mysterious side-effects. Main goals: *Modularity* and *Predictability*. ### Doc Strings A good practice is to include documentations in the form of doc-strings. Doc-strings are strings written immediately after the name of the function. They feed `help()`, IDEs and other tools. ```python def read_prices(filename): ''' Read prices from a CSV file of name,price ''' prices = {} with open(filename) as f: f_csv = csv.reader(f) for row in f_csv: prices[row[0]] = float(row[1]) return prices ``` ### Type Annotations You can also add some optional type annotations to your function definitions. ```python def read_prices(filename: str) -> dict: ''' Read prices from a CSV file of name,price ''' prices = {} with open(filename) as f: f_csv = csv.reader(f) for row in f_csv: prices[row[0]] = float(row[1]) return prices ``` These do nothing. It is purely informational. They may be used by IDEs, code checkers, etc. ## Exercises In section 2, you wrote a program called `report.py` that printed out a report showing the performance of a stock portfolio. This program consisted of some functions. For example: ```python # report.py import csv def read_portfolio(filename): ''' Read a stock portfolio file into a list of dictionaries with keys name, shares, and price. ''' portfolio = [] with open(filename) as f: rows = csv.reader(f) headers = next(rows) for row in rows: record = dict(zip(headers, row)) stock = { 'name' : record['name'], 'shares' : int(record['shares']), 'price' : float(record['price']) } portfolio.append(stock) return portfolio ... ``` However, there were also portions of the program that just performed a series of scripted calculations. This code appeared near the end of the program. For example: ```python ... # Output the report headers = ('Name', 'Shares', 'Price', 'Change') print('%10s %10s %10s %10s' % headers) print(('-' * 10 + ' ') * len(headers)) for row in report: print('%10s %10d %10.2f %10.2f' % row) ... ``` In this exercise, we’re going take this program and organize it a little more strongly around the use of functions. ### Exercise 3.1: Structuring a program as a collection of functions Modify your `report.py` program so that all major operations, including calculations and output, are carried out by a collection of functions. Specifically: * Create a function `print_report(report)` that prints out the report. * Change the last part of the program so that it is nothing more than a series of function calls and no other computation. ### Exercise 3.2: Creating a function for program execution Take the last part of your program and package it into a single function `portfolio_report(portfolio_filename, prices_filename)`. Have the function work so that the following function call creates the report as before: ```python portfolio_report('Data/portfolio.csv', 'Data/prices.csv') ``` In this final version, your program will be nothing more than a series of function definitions followed by a single function call to `portfolio_report()` at the very end (which executes all of the steps involved in the program). By turning your program into a single function, it becomes easy to run it on different inputs. For example, try these statements interactively after running your program: ```python >>> portfolio_report('Data/portfolio2.csv', 'Data/prices.csv') ... look at the output ... >>> files = ['Data/portfolio.csv', 'Data/portfolio2.csv'] >>> for name in files: print(f'{name:-^43s}') portfolio_report(name, 'prices.csv') print() ... look at the output ... >>> ``` [Contents](../Contents) \| [Previous (2.7 Object Model)](../02_Working_with_data/07_Objects) \| [Next (3.2 More on Functions)](02_More_functions)