Slide 1

Slide 1 text

Let’s Build!

Slide 2

Slide 2 text

Demo: accountant.py This is what we plan to build.

Slide 3

Slide 3 text

$  python3  -­‐m  venv  accountant_venv   $  .  accountant_venv/bin/activate   (accountant_venv)  $ >  python3  -­‐m  venv  accountant_venv   >  accountant_venv\Scripts\activate   (accountant_venv)  >

Slide 4

Slide 4 text

project   !""  accountant_venv   #      !""  bin   #      !""  include   #      !""  lib   #      $""  pyvenv.cfg   $""  accountant.py

Slide 5

Slide 5 text

Function to add an item

Slide 6

Slide 6 text

def  _show_items(items):          template  =  '{name:20}{price:>5}'          if  not  items:                  print("No  items.  Use  'add'  to  add  some!")                  return          print()          print(template.format(name='Item',  price='Price'))          print('-­‐'  *  25)          for  item  in  items:                  print(template.format(                          name=item['name'],  price=item['price'],                  ))          print()

Slide 7

Slide 7 text

def  add():          items  =  []          name  =  input('Item  name:  ')          price  =  input('Price:  ')          if  name  and  price:                  items.append({                          'name':  name,  'price':  price,                  })                  _show_items(items)   if  __name__  ==  '__main__':          add()

Slide 8

Slide 8 text

http://d.pr/1c5Bv

Slide 9

Slide 9 text

$  python  accountant.py   What  to  buy:  Apples   Price:  10   Item                                Price             -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐   Apples                                  10

Slide 10

Slide 10 text

Persistence

Slide 11

Slide 11 text

File Objects • For reading files and file-like interfaces • Built-in type file • close(), read(), readline(), seek(), etc.

Slide 12

Slide 12 text

Path Objects • import  pathlib • pathlib.Path • Path.cwd() • desktop  =  home  /  'Desktop' • home  =  desktop.parent

Slide 13

Slide 13 text

import  pathlib   path  =  pathlib.Path('input.txt')   f  =  path.open()   line  =  f.readline()   while  line:          print(line)          line  =  f.readline()   f.close()   print('ALL  DONE')

Slide 14

Slide 14 text

import  pathlib   path  =  pathlib.Path('input.txt')   f  =  path.open()   for  line  in  f:          print(line)   f.close()   print('ALL  DONE')

Slide 15

Slide 15 text

import  pathlib   pathlib.Path('input.txt')   with  path.open()  as  f:          for  line  in  f:                  print(line)   print('ALL  DONE') File closed automatically on exiting.

Slide 16

Slide 16 text

import  pathlib   path  =  pathlib.Path('output.txt')   with  path.open('w')  as  f:          f.write('Hello  world!\n')   print('ALL  DONE')

Slide 17

Slide 17 text

The json module • import  json • json.dump(obj,  f) • json.load(f) 㶷Ⰵ 隟⳿

Slide 18

Slide 18 text

Python types JSON types int, float Number str String list, tuple, etc. Array dict, etc. Object None null

Slide 19

Slide 19 text

import  pathlib   def  _get_save_path():          my_path  =  pathlib.Path(__file__)          save_path  =  my_path.parent  /  'items.json'          return  save_path

Slide 20

Slide 20 text

import  json   def  _load_items():          path  =  _get_save_path()          try:                  with  path.open()  as  f:                          items  =  json.load(f)          except  (FileNotFoundError,  ValueError):                  items  =  []          return  items

Slide 21

Slide 21 text

def  _save_items(items):        #  Your  turn!!  Implement  this.   def  add():          items  =  _load_items()          #  Original  implementation.          _save_items(items)

Slide 22

Slide 22 text

project   !""  accountant_venv   #      !""  ...   !""  accountant.py   $""  items.json

Slide 23

Slide 23 text

$  python  accountant.py   What  to  buy:  Apples   Price:  10   Item                                Price             -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐   Apples                                  10   $  python  accountant.py   What  to  buy:  Oranges   Price:  15   Item                                Price             -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐   Apples                                  10   Oranges                                15

Slide 24

Slide 24 text

Command Line Interface

Slide 25

Slide 25 text

$  python  accountant.py  add   What  to  buy:  Bananas   Price:  7   Item                                Price             -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐   Apples                                  10   Oranges                                15   Bananas                                  7   $  python  accountant.py  show   Item                                Price             -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐   Apples                                  10   Oranges                                15   Bananas                                  7

Slide 26

Slide 26 text

$  pip  install  click   Collecting  click      Downloading  click-­‐4.0-­‐py2.py3-­‐none-­‐any.whl  (62kB)          100%  |████████████████████████|  65kB  1.1MB/s     Installing  collected  packages:  click   Successfully  installed  click-­‐4.0   $

Slide 27

Slide 27 text

pip • Python’s package manager • Manages packages on PyPI (Python Package Index) • pip  install, uninstall, freeze

Slide 28

Slide 28 text

https://pypi.python.org/

Slide 29

Slide 29 text

http://click.pocoo.org/

Slide 30

Slide 30 text

$  pip  freeze  >  requirements.txt

Slide 31

Slide 31 text

project   !""  accountant_venv   #      !""  ...   !""  accountant.py   !""  items.json   $""  requirements.txt

Slide 32

Slide 32 text

Decorators • Modify a callable without re-defining • “Wraps” the target • How is that even possible!?

Slide 33

Slide 33 text

def  hi(name):          print('Hi'  +  name  +'!')   greet  =  hi   greet('Mosky') First-class Functions

Slide 34

Slide 34 text

def  get_name():          return  'TP'   def  hi(name_getter,  words):          def  make_message(words):                  return  '  '.join(words)          print('{msg},  {name}!'.format(                  msg=make_message(words),                  name=name_getter(),          ))   hi(get_name,  ['Hello',  'there'])

Slide 35

Slide 35 text

def  hi(name,  words):          def  make_message():                  return  '  '.join(words)          print('{msg},  {name}!'.format(                  msg=make_message(words),                  name=name,          ))   #  Prints  "Hello  there,  people!"   hi('people',  ['Hello',  'there'])

Slide 36

Slide 36 text

def  outer_wrapper(func)          def  inner_wrapper(name):                  print('Before')                  func(name)                  print('After')          return  inner_wrapper   def  hi(name):          print('Hi,  {}!'.format(name))   #  What  happens  here?   outer_wrapper(hi)('Marty')

Slide 37

Slide 37 text

def  outer_wrapper(func)          def  inner_wrapper(name):                  print('Before')                  func(name)                  print('After')          return  inner_wrapper   def  hi(name):          print('Hi,  {}!'.format(name))   #  What  happens  here?   outer_wrapper(hi)('Marty')

Slide 38

Slide 38 text

def  outer_wrapper(func)          def  inner_wrapper(name):                  print('Before')                  func(name)                  print('After')          return  inner_wrapper   def  hi(name):          print('Hi,  {}!'.format(name))   #  What  happens  here?   outer_wrapper(hi)('Marty')

Slide 39

Slide 39 text

def  outer_wrapper(func)          def  inner_wrapper(name):                  print('Before')                  func(name)                  print('After')          return  inner_wrapper   def  hi(name):          print('Hi,  {}!'.format(name))   #  What  happens  here?   outer_wrapper(hi)('Marty')

Slide 40

Slide 40 text

def  outer_wrapper(func)          def  inner_wrapper(name):                  print('Before')                  func(name)                  print('After')          return  inner_wrapper   def  hi(name):          print('Hi,  {}!'.format(name))   hi  =  outer_wrapper(hi)   hi('Marty')

Slide 41

Slide 41 text

def  outer_wrapper(func)          def  inner_wrapper(name):                  print('Before')                  func(name)                  print('After')          return  inner_wrapper   @outer_wrapper   def  hi(name):          print('Hi,  {}!'.format(name))   hi('Marty')

Slide 42

Slide 42 text

import  click   @click.group()   def  cli():          pass   @cli.add_command   @click.command()   def  add():          #  Implementation  does  not  change.   if  __name__  ==  '__main__':          cli()

Slide 43

Slide 43 text

$  python  accountant.py  add   What  to  buy:  Bananas   Price:  7   Item                                Price             -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐   Apples                                  10   Oranges                                15   Bananas                                  7

Slide 44

Slide 44 text

$  python  accountant.py   #  What  happens  here?   $  python  accountant.py  -­‐-­‐help   #  What  happens  here?

Slide 45

Slide 45 text

$  python  accountant.py  show   Item                                Price             -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐   Apples                                  10   Oranges                                15   Bananas                                  7

Slide 46

Slide 46 text

Item Removal

Slide 47

Slide 47 text

$  python  accountant.py  show   Item                                Price             -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐   Apples                                  10   Oranges                                15   Bananas                                  7   $  python  accountant.py  remove  1   Item                                Price             -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐   Apples                                  10   Bananas                                  7

Slide 48

Slide 48 text

#  remove_test.py   def  remove(index):          items  =  [                  {'name':  'Apples',  'price':  10},                  {'name':  'Oranges',  'price':  15},          ]          #  㻛⡲...          #  㹀纏湫䱸䖰  accountant.py  䭠頺麓⢵կ          _show_items(items)   if  __name__  =  '__main__':          index  =  input('Index:  ')          remove(index)

Slide 49

Slide 49 text

Keyword Arguments • print('Hello',  'World',  sep=',  ') • Named and unnamed arguments • Most arguments can be either

Slide 50

Slide 50 text

def  hi(name,  message):          print('{},  {}!'.format(message,  name))   #  Calling  with  positional  arguments.   hi('Doc',  'Hello')   #  Calling  with  keyword  arguments.   hi(message='Hello',  name='Doc')

Slide 51

Slide 51 text

import  sys   print('Hello',  'World',              sep=',  ',  file=sys.stderr) Variable-length positional arguments keyword-only arguments

Slide 52

Slide 52 text

https://docs.python.org/3/ tutorial/controlflow.html#more- on-defining-functions

Slide 53

Slide 53 text

@cli.add_command   @click.command()   @click.argument('index')   def  remove(index):          items  =  _load_items()          #  ...          #  Before  _show_items(items)          _save_items(items)

Slide 54

Slide 54 text

$  python  accountant.py   #  What  happens  now?   $  python  accountant.py  remove  0   #  What  happens?   $  python  accountant.py  remove   #  What  happens?

Slide 55

Slide 55 text

Refining UI

Slide 56

Slide 56 text

$  python  accountant.py  show      #    Item                                Price             -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐      0    Apples                                  10      1    Oranges                                15      2    Bananas                                  7

Slide 57

Slide 57 text

def  _show_items(items):          template  =  '{i:>3}    {name:20}{price:>5}'          #  ...          for  i  in  range(len(items)):                  item  =  items[i]                  print(template.format(                          i=i,  name=item['name'],                            price=item['price'],                  ))          print()

Slide 58

Slide 58 text

“There must be a better way.”

Slide 59

Slide 59 text

def  _show_items(items):          template  =  '{i:>3}    {name:20}{price:>5}'          #  ...          i  =  0          for  item  in  items:                  print(template.format(                          i=i,  name=item['name'],                            price=item['price'],                  ))                  i  +=  1          print()

Slide 60

Slide 60 text

“There must be a better way.”

Slide 61

Slide 61 text

def  _show_items(items):          template  =  '{i:>3}    {name:20}{price:>5}'          #  ...        for  i,  item  in  zip(range(len(items)),  items):                  print(template.format(                          i=i,  name=item['name'],                            price=item['price'],                  ))        print()

Slide 62

Slide 62 text

def  _show_items(items):          template  =  '{i:>3}    {name:20}{price:>5}'          #  ...        for  i,  item  in  enumerate(items):                  print(template.format(                          i=i,  name=item['name'],                            price=item['price'],                  ))        print()

Slide 63

Slide 63 text

“There must be a better way.”

Slide 64

Slide 64 text

Next Steps • Configurable _get_save_path • configparser module • Save as SQLite and other formats • sqlite3 module • Even more CLI improvements • colorama and palpatine • Any other ideas? Ask!