Loading the chapter…
%23%20%2F%2F%2F%20script%0A%23%20requires-python%20%3D%20%22%3E%3D3.12%2C%3C3.15%22%0A%23%20dependencies%20%3D%20%5B%0A%23%20%20%20%20%20%22marimo%22%2C%0A%23%20%5D%0A%23%20%2F%2F%2F%0A%22%22%22Python%20Handbook%2C%20Chapter%20B%3A%20Collections.%0A%22%22%22%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.25.2%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22%2C%20sql_output%3D%22polars%22)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Collections%0A%0A%20%20%20%20Chapter%20B%20of%20the%20Python%20Handbook.%20Nine%20sections%2C%20each%20one%20concept.%20Chapter%20A%20held%20one%0A%20%20%20%20value%20in%20one%20name.%20This%20chapter%20holds%20many%2C%20and%20the%20shape%20you%20choose%20decides%20what%0A%20%20%20%20questions%20are%20easy%20to%20ask.%0A%0A%20%20%20%20Every%20number%20below%20comes%20from%20orders%20%6010248%60%20to%20%6010252%60%20of%20the%20course%20warehouse%2C%20which%0A%20%20%20%20is%20the%20same%20table%20SQL%20queries%20later%20in%20the%20term.%20Small%20enough%20to%20check%20by%20hand%2C%20and%0A%20%20%20%20real.%0A%0A%20%20%20%20You%20can%20read%20this%20straight%20through%2C%20or%20open%20it%20when%20you%20need%20one%20thing.%20Every%20section%0A%20%20%20%20ends%20with%20three%20questions%20that%20have%20no%20answers%20written%20down%2C%20because%20those%20are%20the%20ones%0A%20%20%20%20asked%20out%20loud%20in%20class.%0A%0A%20%20%20%20To%20run%20the%20code%20yourself%2C%20download%20the%20%60.py%60%20into%20your%20project%20and%20open%20it%20with%0A%20%20%20%20%60uv%20run%20marimo%20edit%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%20%20%20%20%23%23%2011.%20Lists%0A%0A%20%20%20%20A%20list%20holds%20several%20values%20in%20one%20name%2C%20in%20the%20order%20you%20put%20them%20there.%20It%20is%20the%0A%20%20%20%20first%20collection%20you%20reach%20for%20and%20the%20one%20most%20analytics%20code%20is%20built%20out%20of.%0A%0A%20%20%20%20%F0%9F%93%96%20**Used%20in%3A**%20Getting%20everything%20running%20%C2%B7%20What%20one%20row%20means%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Square%20brackets%2C%20commas%2C%20and%20%60len()%60%0A%0A%20%20%20%20The%20freight%20charged%20on%20orders%2010248%20to%2010252.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20freight_charges%20%3D%20%5B16.75%2C%2022.25%2C%2025.00%2C%2020.25%2C%2036.25%5D%0A%0A%20%20%20%20freight_charges%2C%20len(freight_charges)%0A%20%20%20%20return%20(freight_charges%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20add%20a%20sixth%20charge%20to%20the%20literal%20and%20run%20it%20again.%20Then%20run%0A%20%20%20%20%60sum(freight_charges)%60%20and%20%60max(freight_charges)%60%20in%20a%20cell%20of%20your%20own.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Positions%20and%20slices%0A%0A%20%20%20%20%60freight_charges%5B0%5D%60%20is%20the%20first%20one%2C%20and%20the%20number%20in%20the%20brackets%20is%20its%20**index**.%0A%20%20%20%20A%20negative%20index%20counts%20back%20from%20the%20end%2C%20and%20a%20slice%20reads%20as%20**from%20here%20up%20to%20but%0A%20%20%20%20not%20including%20there**.%20This%20is%20the%20same%20counting%20a%20string%20uses%20in%20%C2%A75.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(freight_charges)%3A%0A%20%20%20%20freight_charges%5B0%5D%2C%20freight_charges%5B-1%5D%2C%20freight_charges%5B1%3A3%5D%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20get%20the%20last%20two%20charges%20two%20different%20ways%2C%20one%20with%20a%20negative%20number%0A%20%20%20%20and%20one%20without.%0A%0A%20%20%20%20**The%20trap.**%20There%20are%20five%20charges%20and%20the%20last%20position%20is%204.%20Asking%20for%20position%205%0A%20%20%20%20raises%3A%0A%0A%20%20%20%20%60%60%60python%0A%20%20%20%20freight_charges%5B5%5D%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20%60%60%60%0A%20%20%20%20IndexError%3A%20list%20index%20out%20of%20range%0A%20%20%20%20%60%60%60%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20A%20list%20can%20be%20changed%20in%20place%0A%0A%20%20%20%20This%20is%20the%20difference%20between%20a%20list%20and%20everything%20in%20Chapter%20A.%20A%20string%20method%0A%20%20%20%20hands%20back%20a%20new%20string%3B%20a%20list%20method%20changes%20the%20list%20you%20already%20have%2C%20which%20is%20what%0A%20%20%20%20it%20means%20to%20call%20a%20list%20**mutable**.%20%60.append()%60%20adds%20to%20the%20end%2C%20and%20assigning%20to%20a%0A%20%20%20%20position%20replaces%20what%20was%20there.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20ship_countries%20%3D%20%5B%22France%22%2C%20%22Germny%22%2C%20%22Brazil%22%2C%20%22France%22%5D%0A%20%20%20%20ship_countries%5B1%5D%20%3D%20%22Germany%22%0A%20%20%20%20ship_countries.append(%22Belgium%22)%0A%0A%20%20%20%20ship_countries%2C%20len(ship_countries)%0A%20%20%20%20return%20(ship_countries%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Five%20orders%20shipped%20to%20four%20countries%2C%20because%20France%20appears%20twice.%20Hold%20on%20to%20that%3B%0A%20%20%20%20it%20is%20what%20makes%20%C2%A713%20and%20%C2%A717%20worth%20reading.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20%60.insert(0%2C%20%22Sweden%22)%60%20puts%20a%20value%20at%20a%20position%20and%20pushes%20the%20rest%0A%20%20%20%20along.%20%60.remove(%22Brazil%22)%60%20deletes%20the%20first%20match.%20%60.pop()%60%20takes%20the%20last%20one%20off%20and%0A%20%20%20%20hands%20it%20back%20to%20you.%20Run%20all%20three%20and%20print%20the%20list%20after%20each%20one.%0A%0A%20%20%20%20**%60.append()%60%20adds%20one%20item%2C%20whatever%20you%20hand%20it.**%20Hand%20it%20a%20list%20of%20two%20and%20you%20get%0A%20%20%20%20one%20item%20that%20happens%20to%20be%20a%20list%2C%20and%20%60len()%60%20goes%20up%20by%20one%20rather%20than%20two.%0A%20%20%20%20%60.extend()%60%20is%20the%20one%20that%20adds%20them%20separately.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20%60sorted()%60%20and%20%60.sort()%60%0A%0A%20%20%20%20Two%20ways%20to%20sort%2C%20and%20they%20do%20different%20things%20to%20the%20list%20you%20already%20have.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(freight_charges)%3A%0A%20%20%20%20freight_sorted%20%3D%20sorted(freight_charges)%0A%0A%20%20%20%20sort_demo%20%3D%20%5B16.75%2C%2022.25%2C%2025.00%2C%2020.25%2C%2036.25%5D%0A%20%20%20%20sort_return%20%3D%20sort_demo.sort()%0A%0A%20%20%20%20freight_sorted%2C%20sort_return%2C%20sort_demo%2C%20freight_charges%0A%20%20%20%20return%20(sort_return%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Five%20values%2C%20in%20order.%20%60sorted()%60%20produced%20a%20sorted%20copy%20and%20left%20%60freight_charges%60%0A%20%20%20%20in%20its%20original%20order.%20%60.sort()%60%20put%20%60sort_demo%60%20in%20order%20and%20handed%20back%20%60None%60.%0A%0A%20%20%20%20**The%20trap%2C%20and%20it%20is%20the%20most%20common%20one%20in%20this%20section.**%20%60.sort()%60%20returns%20nothing%2C%0A%20%20%20%20so%20a%20line%20that%20looks%20like%20the%20obvious%20way%20to%20write%20it%20throws%20your%20data%20away%3A%0A%0A%20%20%20%20%60%60%60python%0A%20%20%20%20charges%20%3D%20%5B16.75%2C%2022.25%2C%2025.00%5D%0A%20%20%20%20charges%20%3D%20charges.sort()%20%20%20%20%20%20%23%20charges%20is%20now%20None%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20Nothing%20raises%20on%20that%20line.%20The%20failure%20arrives%20later%2C%20wherever%20%60charges%60%20gets%20used.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(sort_return)%3A%0A%20%20%20%20sort_return%20is%20None%2C%20type(sort_return)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20run%20%60sort_return%5B0%5D%60%20in%20a%20cell%20of%20your%20own%20and%20read%20the%20error.%20That%20is%0A%20%20%20%20the%20message%20you%20would%20actually%20meet%2C%20several%20cells%20away%20from%20the%20line%20that%20caused%20it.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Names%20that%20share%20a%20list%0A%0A%20%20%20%20%60%3D%60%20puts%20a%20value%20into%20a%20name%2C%20and%20for%20a%20list%20that%20value%20is%20the%20list%20itself.%20Two%20names%0A%20%20%20%20can%20point%20at%20one%20list%2C%20each%20an%20**alias**%20for%20the%20other%2C%20and%20a%20change%20through%20either%20name%0A%20%20%20%20is%20visible%20through%20both.%20%60.copy()%60%20is%20how%20you%20get%20a%20second%20list.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20original_freight%20%3D%20%5B16.75%2C%2022.25%2C%2025.00%5D%0A%20%20%20%20same_list%20%3D%20original_freight%0A%20%20%20%20freight_copy%20%3D%20original_freight.copy()%0A%0A%20%20%20%20same_list%5B0%5D%20%3D%2099.99%0A%0A%20%20%20%20original_freight%2C%20freight_copy%2C%20same_list%20is%20original_freight%2C%20freight_copy%20is%20original_freight%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20One%20assignment%2C%20through%20%60same_list%60%2C%20and%20%60original_freight%60%20changed%20with%20it.%0A%20%20%20%20%60freight_copy%60%20did%20not.%0A%0A%20%20%20%20%60is%60%20and%20%60%3D%3D%60%20answer%20different%20questions.%20%60%3D%3D%60%20asks%20whether%20two%20lists%20hold%20equal%0A%20%20%20%20values.%20%60is%60%20asks%20whether%20there%20is%20only%20one%20list%2C%20which%20is%20a%20question%20about%20**identity**.%0A%20%20%20%20Two%20separate%20lists%20holding%20the%20same%20three%20numbers%20are%20%60%3D%3D%60%20and%20are%20not%20%60is%60.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20add%20%60original_freight%20%3D%3D%20freight_copy%60%20to%20that%20cell%20before%20the%0A%20%20%20%20assignment%20line%2C%20and%20again%20after%20it.%20The%20answer%20changes%20and%20the%20%60is%60%20answers%20do%20not.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20In%20Excel%20terms%0A%0A%20%20%20%20Excel's%20**Data%20%3E%20Sort**%20rewrites%20the%20sheet.%20There%20is%20no%20version%20of%20it%20that%20hands%20you%20a%0A%20%20%20%20sorted%20copy%20and%20leaves%20the%20sheet%20alone%2C%20so%20the%20habit%20is%20to%20expect%20a%20sort%20to%20*be*%20the%0A%20%20%20%20answer.%20%60sorted()%60%20is%20the%20version%20Excel%20does%20not%20have%2C%20and%20%60.sort()%60%20is%20the%20one%20it%20does.%0A%20%20%20%20Writing%20%60x%20%3D%20lst.sort()%60%20is%20that%20Excel%20habit%20reaching%20for%20the%20wrong%20one.%0A%0A%20%20%20%20%23%23%23%20%E2%9C%94%20Check%20your%20understanding%0A%0A%20%20%20%201.%20%60sorted(charges)%60%20and%20%60charges.sort()%60%20both%20put%20five%20numbers%20in%20order.%20Describe%20what%0A%20%20%20%20%20%20%20each%20one%20leaves%20behind%20afterward.%0A%20%20%20%202.%20You%20write%20%60charges%20%3D%20charges.sort()%60%20and%20three%20cells%20later%20something%20fails.%20What%0A%20%20%20%20%20%20%20does%20%60charges%60%20hold%2C%20and%20why%20did%20the%20failure%20not%20happen%20on%20the%20line%20you%20wrote%3F%0A%20%20%20%203.%20%60b%20%3D%20a%60%20and%20%60b%20%3D%20a.copy()%60%20both%20give%20you%20a%20name%20%60b%60%20holding%20three%20numbers.%20Give%20a%0A%20%20%20%20%20%20%20situation%20where%20the%20difference%20between%20them%20changes%20an%20answer.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%20%20%20%20%23%23%2012.%20Iterating%20over%20a%20list%20with%20%60for%60%0A%0A%20%20%20%20A%20%60for%60%20loop%20runs%20the%20same%20block%20of%20code%20once%20for%20each%20item%20in%20a%20list%2C%20which%20is%20what%20it%0A%20%20%20%20means%20to%20**iterate**%20over%20the%20list%2C%20and%20anything%20you%20can%20loop%20over%20this%20way%20is%20an%0A%20%20%20%20**iterable**.%20This%20is%20where%20code%20stops%20describing%20one%20thing%20and%20starts%20describing%20a%0A%20%20%20%20procedure%20that%20scales%20to%20a%20million%20rows%20without%20changing.%0A%0A%20%20%20%20%F0%9F%93%96%20**Used%20in%3A**%20What%20one%20row%20means%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20The%20shape%20of%20a%20loop%0A%0A%20%20%20%20The%20line%20ends%20in%20a%20colon%20and%20the%20block%20underneath%20is%20indented%2C%20the%20same%20shape%20as%20an%0A%20%20%20%20%60if%60%20in%20%C2%A74.%20The%20name%20between%20%60for%60%20and%20%60in%60%20is%20yours%20to%20choose%2C%20and%20it%20holds%20one%20item%0A%20%20%20%20at%20a%20time.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(freight_charges)%3A%0A%20%20%20%20for%20charge%20in%20freight_charges%3A%0A%20%20%20%20%20%20%20%20print(charge)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20rename%20%60charge%60%20to%20%60c%60%20and%20run%20it%20again.%20Nothing%20changes%20except%20how%0A%20%20%20%20readable%20the%20loop%20is.%20Then%2C%20with%20whichever%20name%20you%20settled%20on%2C%20print%20it%20formatted%3A%0A%20%20%20%20%60f%22%7Bcharge%3A.2f%7D%22%60%2C%20so%20every%20line%20has%20two%20decimals.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Building%20a%20total%0A%0A%20%20%20%20A%20running%20total%20needs%20a%20name%20that%20exists%20before%20the%20loop%20starts.%20Each%20pass%20adds%20one%0A%20%20%20%20item%20to%20it.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(freight_charges)%3A%0A%20%20%20%20freight_running_total%20%3D%200.0%0A%0A%20%20%20%20for%20each_charge%20in%20freight_charges%3A%0A%20%20%20%20%20%20%20%20freight_running_total%20%3D%20freight_running_total%20%2B%20each_charge%0A%0A%20%20%20%20freight_running_total%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20**The%20trap.**%20Move%20%60freight_running_total%20%3D%200.0%60%20inside%20the%20loop%20and%20it%20is%20reset%20on%0A%20%20%20%20every%20pass%3A%0A%0A%20%20%20%20%60%60%60python%0A%20%20%20%20for%20each_charge%20in%20freight_charges%3A%0A%20%20%20%20%20%20%20%20freight_running_total%20%3D%200.0%0A%20%20%20%20%20%20%20%20freight_running_total%20%3D%20freight_running_total%20%2B%20each_charge%0A%20%20%20%20%23%20freight_running_total%20is%2036.25%2C%20the%20last%20charge%2C%20not%20120.5%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20One%20line%20moves%20and%20the%20answer%20stops%20being%20a%20total.%20Nothing%20raises%2C%20and%2036.25%20is%20a%0A%20%20%20%20plausible%20freight%20number.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20run%20both%20versions%20and%20say%20the%20two%20answers%20out%20loud.%20**Rename%20the%20total%0A%20%20%20%20in%20your%20copy**%2C%20to%20%60broken_running_total%60%2C%20because%20a%20name%20is%20defined%20in%20exactly%20one%20cell%0A%20%20%20%20here%20and%20a%20second%20%60freight_running_total%60%20is%20a%20multiple-definitions%20error%20rather%20than%0A%20%20%20%20the%20lesson.%20Then%20predict%20what%20happens%20if%20you%20move%20the%20%600.0%60%20line%20inside%20the%20loop%20but%20put%0A%20%20%20%20the%20total%20on%20the%20line%20*after*%20the%20loop%20ends.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20%60enumerate%60%20when%20you%20need%20the%20position%20too%0A%0A%20%20%20%20Most%20loops%20need%20the%20item%20and%20nothing%20else.%20When%20you%20also%20need%20to%20know%20which%20one%20it%20is%2C%0A%20%20%20%20%60enumerate%60%20hands%20you%20both%2C%20and%20%60start%3D1%60%20counts%20the%20way%20a%20person%20would.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(freight_charges)%3A%0A%20%20%20%20for%20position%2C%20listed_charge%20in%20enumerate(freight_charges%2C%20start%3D1)%3A%0A%20%20%20%20%20%20%20%20print(f%22%7Bposition%7D.%20%7Blisted_charge%3A%3E6.2f%7D%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20drop%20%60start%3D1%60%20and%20run%20it%20again.%20Then%20print%20the%20order%20number%20instead%20of%0A%20%20%20%20the%20position%2C%20using%20%6010247%20%2B%20position%60.%0A%0A%20%20%20%20**A%20pointer%20forward.**%20A%20loop%20that%20only%20builds%20a%20new%20list%20from%20an%20old%20one%20can%20be%0A%20%20%20%20written%20on%20one%20line%2C%20and%20agent-written%20Python%20does%20this%20constantly.%20That%20one%20line%20is%0A%20%20%20%20called%20a%20comprehension%2C%20it%20is%20the%20same%20loop%2C%20and%20%C2%A718%20is%20where%20you%20read%20one.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20%60while%60%20repeats%20until%20its%20condition%20is%20%60False%60%0A%0A%20%20%20%20A%20%60for%60%20loop%20makes%20one%20pass%20per%20item.%20%60while%60%20is%20for%20the%20case%20where%20the%20number%20of%0A%20%20%20%20passes%20is%20unknown%3A%20it%20checks%20a%20condition%20before%20every%20pass%20and%20stops%20the%20first%20time%0A%20%20%20%20the%20condition%20is%20%60False%60.%20Here%20it%20counts%20the%20years%20until%20an%20investment%20growing%20at%207%25%0A%20%20%20%20doubles.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20growth_rate%20%3D%200.07%0A%20%20%20%20investment_value%20%3D%2010_000.00%0A%20%20%20%20years_to_double%20%3D%200%0A%0A%20%20%20%20while%20investment_value%20%3C%2020_000%3A%0A%20%20%20%20%20%20%20%20investment_value%20%3D%20investment_value%20*%20(1%20%2B%20growth_rate)%0A%20%20%20%20%20%20%20%20years_to_double%20%3D%20years_to_double%20%2B%201%0A%0A%20%20%20%20years_to_double%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Something%20inside%20the%20loop%20has%20to%20move%20the%20condition%20toward%20%60False%60.%20At%20a%0A%20%20%20%20%60growth_rate%60%20of%20%600%60%20the%20value%20never%20changes%20and%20the%20cell%20runs%20until%20you%20press%20stop.%0A%0A%20%20%20%20Code%20an%20agent%20writes%20often%20uses%20%60while%20True%3A%60%20with%20a%20%60break%60%20inside%2C%20and%20%60break%60%20ends%0A%20%20%20%20the%20loop%20on%20the%20spot.%20The%20agent%20loop%20in%0A%20%20%20%20%5B%C2%A737%5D(%2Fhandbooks%2Fpython%2F04-agents-and-apis%2F%2337-the-agent-loop)%20has%20this%20shape.%20Read%0A%20%20%20%20it%20as%20%22repeat%20until%22%2C%20then%20find%20the%20line%20that%20ends%20it.%20When%20each%20pass%20costs%20money%2C%20as%0A%20%20%20%20an%20API%20call%20does%2C%20give%20the%20loop%20a%20ceiling%20instead%3A%0A%0A%20%20%20%20%60%60%60python%0A%20%20%20%20for%20attempt%20in%20range(5)%3A%20%20%20%20%23%20at%20most%20five%20passes%0A%20%20%20%20%20%20%20%20...%0A%20%20%20%20%20%20%20%20if%20done%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20%23%23%23%20%E2%9C%94%20Check%20your%20understanding%0A%0A%20%20%20%201.%20What%20does%20the%20name%20between%20%60for%60%20and%20%60in%60%20hold%20on%20the%20third%20pass%20of%20a%20loop%20over%20five%0A%20%20%20%20%20%20%20charges%3F%0A%20%20%20%202.%20A%20colleague's%20total%20comes%20out%20as%20the%20last%20value%20in%20the%20list%20every%20time.%20Where%20is%20the%0A%20%20%20%20%20%20%20bug%2C%20and%20what%20is%20the%20symptom%20telling%20you%3F%0A%20%20%20%203.%20When%20would%20you%20reach%20for%20%60enumerate%60%20instead%20of%20a%20plain%20%60for%60%3F%0A%20%20%20%204.%20A%20%60while%60%20loop%20has%20been%20running%20for%20a%20minute.%20Which%20line%20do%20you%20read%20first%2C%20and%20what%0A%20%20%20%20%20%20%20are%20you%20looking%20for%20in%20it%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%20%20%20%20%23%23%2013.%20Filtering%20and%20the%20accumulator%0A%0A%20%20%20%20An%20%60if%60%20inside%20a%20loop%20keeps%20some%20items%20and%20skips%20the%20rest.%20An%20accumulator%20carries%20a%0A%20%20%20%20running%20answer%20across%20the%20passes.%20Put%20the%20two%20together%20and%20you%20have%20written%20what%20SQL%0A%20%20%20%20calls%20%60WHERE%60%20and%20%60GROUP%20BY%60%2C%20by%20hand%2C%20before%20you%20have%20met%20either%20one.%0A%0A%20%20%20%20%F0%9F%93%96%20**Used%20in%3A**%20What%20one%20row%20means%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20%60if%60%20inside%20the%20loop%20keeps%20some%20items%0A%0A%20%20%20%20Start%20with%20an%20empty%20list%2C%20test%20each%20item%2C%20and%20append%20the%20ones%20that%20pass.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(freight_charges)%3A%0A%20%20%20%20heavy_freight%20%3D%20%5B%5D%0A%0A%20%20%20%20for%20candidate%20in%20freight_charges%3A%0A%20%20%20%20%20%20%20%20if%20candidate%20%3E%2022%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20heavy_freight.append(candidate)%0A%0A%20%20%20%20heavy_freight%2C%20len(heavy_freight)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Three%20of%20the%20five%20charges%20are%20above%2022.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20change%20%60%3E%2022%60%20to%20%60%3E%3D%2022.25%60%20and%20predict%20the%20count%20before%20you%20run%20it.%0A%20%20%20%20Then%20write%20the%20filter%20that%20keeps%20the%20charges%20*below*%20the%20average%20of%2024.10.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20A%20list%20of%20records%0A%0A%20%20%20%20A%20list%20of%20numbers%20can%20be%20totalled.%20Answering%20*which%20country*%20costs%20the%20most%20needs%20the%0A%20%20%20%20country%20attached%20to%20the%20charge%2C%20which%20means%20each%20item%20carries%20several%20named%20fields.%0A%0A%20%20%20%20The%20shape%20below%20is%20a%20**dictionary**%2C%20one%20per%20order%2C%20and%20%C2%A715%20gives%20dictionaries%20their%20own%0A%20%20%20%20section.%20Here%20it%20is%20only%20the%20thing%20being%20looped%20over%3A%20%60order%5B%22ship_country%22%5D%60%20reads%20one%0A%20%20%20%20field%20out%20of%20one%20order.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20orders%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%7B%22order_id%22%3A%2010248%2C%20%22ship_country%22%3A%20%22France%22%2C%20%22freight%22%3A%2016.75%2C%20%22days_to_ship%22%3A%2012%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22order_id%22%3A%2010249%2C%20%22ship_country%22%3A%20%22Germany%22%2C%20%22freight%22%3A%2022.25%2C%20%22days_to_ship%22%3A%205%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22order_id%22%3A%2010250%2C%20%22ship_country%22%3A%20%22Brazil%22%2C%20%22freight%22%3A%2025.00%2C%20%22days_to_ship%22%3A%204%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22order_id%22%3A%2010251%2C%20%22ship_country%22%3A%20%22France%22%2C%20%22freight%22%3A%2020.25%2C%20%22days_to_ship%22%3A%207%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22order_id%22%3A%2010252%2C%20%22ship_country%22%3A%20%22Belgium%22%2C%20%22freight%22%3A%2036.25%2C%20%22days_to_ship%22%3A%202%7D%2C%0A%20%20%20%20%5D%0A%0A%20%20%20%20len(orders)%2C%20orders%5B0%5D%5B%22ship_country%22%5D%2C%20orders%5B0%5D%5B%22freight%22%5D%0A%20%20%20%20return%20(orders%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20print%20the%20country%20and%20the%20freight%20of%20the%20last%20order%2C%20using%20a%20negative%0A%20%20%20%20position.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20A%20rate%20from%20accumulators%0A%0A%20%20%20%20A%20count%20and%20a%20total%20are%20both%20accumulators.%20Keep%20them%20side%20by%20side%20and%20you%20can%20report%20an%0A%20%20%20%20average%20and%20a%20share%20from%20one%20pass%20over%20the%20data.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(orders)%3A%0A%20%20%20%20slow_count%20%3D%200%0A%20%20%20%20days_total%20%3D%200%0A%0A%20%20%20%20for%20timed_order%20in%20orders%3A%0A%20%20%20%20%20%20%20%20days_total%20%3D%20days_total%20%2B%20timed_order%5B%22days_to_ship%22%5D%0A%20%20%20%20%20%20%20%20if%20timed_order%5B%22days_to_ship%22%5D%20%3E%3D%207%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20slow_count%20%3D%20slow_count%20%2B%201%0A%0A%20%20%20%20days_total%2C%20slow_count%2C%20days_total%20%2F%20len(orders)%2C%20slow_count%20%2F%20len(orders)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20The%20five%20orders%20took%2030%20days%20between%20them%2C%20so%20a%20mean%20of%206.0%2C%20and%20two%20of%20them%20took%20a%0A%20%20%20%20week%20or%20longer%2C%20which%20is%200.4%20of%20them.%0A%0A%20%20%20%20**The%20trap.**%20%60days_total%20%2F%20len(orders)%60%20divides%20by%20the%20number%20of%20orders%20you%20started%0A%20%20%20%20with.%20If%20the%20loop%20had%20skipped%20some%20of%20them%2C%20that%20denominator%20is%20wrong%20and%20the%20average%20is%0A%20%20%20%20quietly%20too%20low.%20Count%20what%20you%20actually%20included.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20add%20a%20second%20counter%20that%20only%20increments%20inside%20the%20%60if%60%2C%20and%20divide%20the%0A%20%20%20%20total%20days%20of%20the%20slow%20orders%20by%20it.%20Explain%20what%20that%20number%20means%20and%20how%20it%20differs%20from%0A%20%20%20%206.0.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20%60continue%60%20skips%20the%20rest%20of%20this%20pass%0A%0A%20%20%20%20An%20early%20%60continue%60%20reads%20as%20a%20filter%20at%20the%20top%20of%20the%20loop%2C%20which%20keeps%20the%0A%20%20%20%20interesting%20work%20out%20of%20an%20indented%20block.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(orders)%3A%0A%20%20%20%20france_freight%20%3D%200.0%0A%0A%20%20%20%20for%20scanned_order%20in%20orders%3A%0A%20%20%20%20%20%20%20%20if%20scanned_order%5B%22ship_country%22%5D%20!%3D%20%22France%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20france_freight%20%3D%20france_freight%20%2B%20scanned_order%5B%22freight%22%5D%0A%0A%20%20%20%20france_freight%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Order%20%6010248%60%20cost%2016.75%20and%20order%20%6010251%60%20cost%2020.25%2C%20so%20France%20comes%20to%2037.0.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20rewrite%20that%20loop%20with%20an%20%60if%60%20around%20the%20addition%20and%20no%20%60continue%60.%0A%20%20%20%20Both%20give%2037.0.%20Decide%20which%20one%20you%20would%20rather%20read%20at%206pm.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Aggregating%20by%20key%0A%0A%20%20%20%20The%20loop%20above%20answers%20one%20country%20at%20a%20time.%20Doing%20every%20country%20at%20once%20needs%20a%20place%0A%20%20%20%20to%20keep%20a%20running%20total%20*per%20country*%2C%20and%20that%20place%20is%20a%20dictionary%3A%20the%20country%20is%0A%20%20%20%20the%20key%2C%20the%20running%20total%20is%20the%20value.%0A%0A%20%20%20%20Three%20steps%2C%20once%20per%20order.%20Read%20the%20key%20out%20of%20the%20record.%20Make%20sure%20it%20has%20a%20slot.%0A%20%20%20%20Add%20this%20order's%20freight%20to%20whatever%20the%20slot%20already%20holds.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(orders)%3A%0A%20%20%20%20freight_by_country%20%3D%20%7B%7D%0A%0A%20%20%20%20for%20grouped_order%20in%20orders%3A%0A%20%20%20%20%20%20%20%20country%20%3D%20grouped_order%5B%22ship_country%22%5D%0A%20%20%20%20%20%20%20%20if%20country%20not%20in%20freight_by_country%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20freight_by_country%5Bcountry%5D%20%3D%200.0%0A%20%20%20%20%20%20%20%20freight_by_country%5Bcountry%5D%20%3D%20freight_by_country%5Bcountry%5D%20%2B%20grouped_order%5B%22freight%22%5D%0A%0A%20%20%20%20freight_by_country%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Four%20keys%20out%20of%20five%20orders%2C%20and%20France%20holds%2037.0%20because%20two%20orders%20landed%20in%20it.%0A%20%20%20%20The%20SQL%20that%20returns%20this%20same%20answer%20is%20one%20statement%2C%20and%20you%20will%20meet%20it%20in%20the%20SQL%0A%20%20%20%20handbook%3A%0A%0A%20%20%20%20%60%60%60sql%0A%20%20%20%20SELECT%20%22ShipCountry%22%2C%20SUM(%22Freight%22)%0A%20%20%20%20FROM%20orders%0A%20%20%20%20WHERE%20%22OrderID%22%20BETWEEN%2010248%20AND%2010252%0A%20%20%20%20GROUP%20BY%20%22ShipCountry%22%3B%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20The%20loop%20above%20is%20what%20the%20database%20does.%20Knowing%20that%20is%20why%20%60GROUP%20BY%60%20will%20not%20feel%0A%20%20%20%20like%20magic.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20change%20the%20value%20being%20added%20from%20%60grouped_order%5B%22freight%22%5D%60%20to%20%601%60%20and%0A%20%20%20%20you%20have%20a%20count%20per%20country%20instead%20of%20a%20sum.%20Predict%20all%20four%20numbers%20before%20you%20run%0A%20%20%20%20it.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20In%20Excel%20terms%0A%0A%20%20%20%20%60SUMIF%60%20and%20a%20pivot%20table%20both%20do%20this%2C%20and%20both%20hide%20the%20loop.%20The%20habit%20that%0A%20%20%20%20misleads%20is%20case%3A%20Excel's%20%60SUMIF%60%20criteria%20are%20case-insensitive%2C%20so%20%60france%60%20and%0A%20%20%20%20%60France%60%20land%20in%20one%20bucket%20without%20you%20asking.%20A%20dictionary%20key%20is%20case-sensitive%2C%20so%0A%20%20%20%20the%20same%20two%20spellings%20become%20two%20entries%2C%20each%20with%20part%20of%20the%20answer.%20Nothing%20warns%0A%20%20%20%20you%2C%20and%20both%20numbers%20look%20reasonable.%0A%0A%20%20%20%20%23%23%23%20%E2%9C%94%20Check%20your%20understanding%0A%0A%20%20%20%201.%20Five%20orders%20go%20in%20and%20the%20dictionary%20comes%20out%20with%20four%20keys.%20Where%20did%20the%20fifth%0A%20%20%20%20%20%20%20order%20go%3F%0A%20%20%20%202.%20Your%20average%20days-to-ship%20is%20computed%20as%20%60total%20%2F%20len(orders)%60%20inside%20a%20loop%20that%0A%20%20%20%20%20%20%20skips%20cancelled%20orders.%20What%20is%20wrong%20with%20the%20answer%2C%20and%20which%20direction%20is%20it%0A%20%20%20%20%20%20%20wrong%20in%3F%0A%20%20%20%203.%20A%20country%20is%20spelled%20%60%22France%22%60%20in%20four%20rows%20and%20%60%22france%22%60%20in%20one.%20What%20does%20the%0A%20%20%20%20%20%20%20aggregate%20look%20like%2C%20and%20how%20would%20you%20notice%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%20%20%20%20%23%23%2014.%20Tuples%0A%0A%20%20%20%20A%20tuple%20holds%20several%20values%20in%20order%2C%20like%20a%20list%2C%20and%20is%20**immutable**%2C%20so%20it%20cannot%0A%20%20%20%20be%20changed%20after%20it%20is%20made.%20The%20second%20half%20is%20the%20whole%20point%2C%20and%20it%20buys%20you%20two%0A%20%20%20%20things%20a%20list%20cannot%20offer.%0A%0A%20%20%20%20%F0%9F%93%96%20**Used%20in%3A**%20Choosing%20a%20data%20structure%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Tuples%0A%0A%20%20%20%20One%20line%20of%20order%20%6010248%60%3A%20a%20product%2C%20a%20quantity%2C%20a%20unit%20price.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20first_line%20%3D%20(%22Queso%20Cabrales%22%2C%2012%2C%2014.00)%0A%0A%20%20%20%20first_line%2C%20len(first_line)%2C%20first_line%5B0%5D%0A%20%20%20%20return%20(first_line%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20**The%20trap.**%20Everything%20a%20list%20can%20do%20to%20itself%2C%20a%20tuple%20refuses%3A%0A%0A%20%20%20%20%60%60%60python%0A%20%20%20%20first_line%5B1%5D%20%3D%2020%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20%60%60%60%0A%20%20%20%20TypeError%3A%20'tuple'%20object%20does%20not%20support%20item%20assignment%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20run%20%60first_line.append(9.80)%60%20and%20read%20which%20of%20the%20two%20things%20it%20tells%0A%20%20%20%20you.%20The%20message%20names%20the%20missing%20method%2C%20and%20the%20reason%20it%20is%20missing%20is%20the%0A%20%20%20%20paragraph%20above.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Unpacking%20gives%20each%20part%20its%20own%20name%0A%0A%20%20%20%20Three%20names%20on%20the%20left%2C%20one%20tuple%20on%20the%20right%2C%20and%20the%20parts%20line%20up%20by%20position.%0A%20%20%20%20This%20is%20**unpacking**%2C%20and%20it%20is%20also%20how%20a%20function%20returns%20several%20values%20at%20once%2C%0A%20%20%20%20because%20%60return%20total%2C%20count%60%20hands%20back%20one%20tuple.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(first_line)%3A%0A%20%20%20%20product_name%2C%20line_quantity%2C%20line_price%20%3D%20first_line%0A%0A%20%20%20%20product_name%2C%20line_quantity%20*%20line_price%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%2012%20at%2014.00%20comes%20to%20168.0%2C%20which%20is%20the%20number%20you%20would%20check%20by%20hand.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20unpack%20it%20into%20two%20names%20instead%20of%20three%20and%20read%20the%20error.%20Then%20write%0A%20%20%20%20a%20function%20that%20takes%20a%20quantity%20and%20a%20price%20and%20returns%20both%20the%20line%20total%20and%20the%0A%20%20%20%20quantity%2C%20as%20a%20tuple.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20When%20a%20tuple%20is%20the%20right%20answer%0A%0A%20%20%20%20A%20list%20is%20the%20default.%20Three%20situations%20turn%20that%20around%2C%20and%20all%20three%20are%20triggers%20you%0A%20%20%20%20can%20check%2C%20and%20not%20qualities%20to%20weigh%20up.%0A%0A%20%20%20%201.%20**The%20number%20of%20parts%20is%20fixed%20and%20each%20position%20means%20something.**%20A%20line%20is%20always%0A%20%20%20%20%20%20%20a%20product%2C%20a%20quantity%20and%20a%20price.%20Appending%20a%20fourth%20thing%20to%20it%20would%20be%20a%20bug%2C%20and%0A%20%20%20%20%20%20%20a%20tuple%20makes%20that%20bug%20impossible.%0A%20%20%20%202.%20**Something%20else%20is%20going%20to%20hold%20on%20to%20it.**%20A%20tuple%20you%20hand%20to%20another%20function%0A%20%20%20%20%20%20%20cannot%20come%20back%20changed%2C%20which%20removes%20a%20class%20of%20surprise%20from%20code%20you%20did%20not%0A%20%20%20%20%20%20%20write.%0A%20%20%20%203.%20**You%20need%20it%20as%20a%20dictionary%20key.**%20This%20one%20is%20not%20a%20preference.%20A%20list%20cannot%20be%20a%0A%20%20%20%20%20%20%20key%20and%20a%20tuple%20can.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20A%20tuple%20as%20a%20dictionary%20key%0A%0A%20%20%20%20%C2%A713%20grouped%20freight%20by%20one%20field.%20Grouping%20by%20two%20fields%20at%20once%20needs%20a%20key%20made%20of%0A%20%20%20%20both%2C%20and%20a%20tuple%20is%20what%20that%20key%20is.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20freight_by_country_year%20%3D%20%7B%0A%20%20%20%20%20%20%20%20(%22France%22%2C%202016)%3A%2037.00%2C%0A%20%20%20%20%20%20%20%20(%22Germany%22%2C%202016)%3A%2022.25%2C%0A%20%20%20%20%20%20%20%20(%22Brazil%22%2C%202016)%3A%2025.00%2C%0A%20%20%20%20%20%20%20%20(%22Belgium%22%2C%202016)%3A%2036.25%2C%0A%20%20%20%20%7D%0A%0A%20%20%20%20freight_by_country_year%5B(%22France%22%2C%202016)%5D%2C%20len(freight_by_country_year)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20try%20the%20same%20dictionary%20with%20%60%5B%22France%22%2C%202016%5D%60%20as%20a%20key%20instead.%20The%0A%20%20%20%20error%20names%20the%20property%20a%20key%20has%20to%20have.%20That%20property%20is%20being%20**hashable**%2C%20and%20a%0A%20%20%20%20list%20does%20not%20have%20it.%0A%0A%20%20%20%20%23%23%23%20%E2%9C%94%20Check%20your%20understanding%0A%0A%20%20%20%201.%20A%20tuple%20and%20a%20list%20both%20hold%20three%20values%20in%20order.%20Name%20one%20thing%20you%20can%20do%20to%20a%0A%20%20%20%20%20%20%20list%20that%20you%20cannot%20do%20to%20a%20tuple%2C%20and%20explain%20why%20that%20is%20sometimes%20what%20you%20want.%0A%20%20%20%202.%20You%20need%20to%20total%20revenue%20by%20region%20and%20channel%20together.%20What%20is%20the%20key%2C%20and%20what%0A%20%20%20%20%20%20%20type%20is%20it%3F%0A%20%20%20%203.%20A%20function%20returns%20%60return%20total%2C%20count%60.%20What%20type%20did%20the%20caller%20receive%2C%20and%20how%0A%20%20%20%20%20%20%20do%20they%20get%20the%20two%20numbers%20apart%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%20%20%20%20%23%23%2015.%20Dictionaries%0A%0A%20%20%20%20A%20dictionary%20stores%20values%20by%20name%20instead%20of%20by%20position.%20%60order%5B%22freight%22%5D%60%20says%20what%0A%20%20%20%20it%20reads%3B%20%60order%5B2%5D%60%20does%20not.%20Everything%20a%20row%20of%20data%20is%2C%20in%20Python%2C%20is%20a%20dictionary.%0A%0A%20%20%20%20%F0%9F%93%96%20**Used%20in%3A**%20Choosing%20a%20data%20structure%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Keys%2C%20values%2C%20and%20access%20by%20key%0A%0A%20%20%20%20Braces%2C%20and%20each%20entry%20is%20%60key%3A%20value%60.%20Order%20%6010248%60%20in%20full.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20order_10248%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22order_id%22%3A%2010248%2C%0A%20%20%20%20%20%20%20%20%22ship_country%22%3A%20%22France%22%2C%0A%20%20%20%20%20%20%20%20%22freight%22%3A%2016.75%2C%0A%20%20%20%20%20%20%20%20%22ordered%22%3A%20%222016-07-04%22%2C%0A%20%20%20%20%20%20%20%20%22shipped%22%3A%20%222016-07-16%22%2C%0A%20%20%20%20%7D%0A%0A%20%20%20%20order_10248%5B%22ship_country%22%5D%2C%20order_10248%5B%22freight%22%5D%2C%20len(order_10248)%0A%20%20%20%20return%20(order_10248%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Five%20fields%2C%20and%20%60len()%60%20counts%20the%20keys.%20It%20says%20nothing%20about%20the%20values.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20read%20the%20two%20dates%20out%20and%20compare%20them%20as%20strings.%20Then%20state%20what%20%C2%A77%20of%0A%20%20%20%20Chapter%20A%20would%20make%20you%20do%20before%20trusting%20that%20comparison.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20A%20missing%20key%20and%20%60.get()%60%0A%0A%20%20%20%20Asking%20for%20a%20key%20that%20is%20not%20there%20stops%20the%20program%3A%0A%0A%20%20%20%20%60%60%60python%0A%20%20%20%20order_10248%5B%22discount%22%5D%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20%60%60%60%0A%20%20%20%20KeyError%3A%20'discount'%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20%60.get()%60%20reads%20the%20same%20key%20and%20hands%20back%20a%20default%20when%20it%20is%20missing.%20It%20is%20the%0A%20%20%20%20one-line%20version%20of%20the%20%60if%20country%20not%20in%20freight_by_country%60%20line%20%C2%A713%20wrote%20out.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(order_10248)%3A%0A%20%20%20%20discount_10248%20%3D%20order_10248.get(%22discount%22%2C%200.0)%0A%20%20%20%20country_10248%20%3D%20order_10248.get(%22ship_country%22%2C%20%22unknown%22)%0A%0A%20%20%20%20discount_10248%2C%20country_10248%2C%20%22discount%22%20in%20order_10248%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20**The%20trap.**%20A%20default%20is%20a%20decision.%20%60order.get(%22discount%22%2C%200.0)%60%20says%20a%20missing%0A%20%20%20%20discount%20means%20no%20discount%2C%20and%20that%20is%20a%20business%20claim%20about%20your%20data.%20Where%20a%0A%20%20%20%20missing%20field%20means%20*nobody%20filled%20this%20in*%2C%20%600.0%60%20is%20a%20number%20you%20invented%20and%20it%20will%0A%20%20%20%20be%20averaged%20with%20the%20real%20ones.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20call%20%60.get(%22discount%22)%60%20with%20no%20default%20and%20print%20what%20comes%20back.%20Then%0A%20%20%20%20add%20%601%60%20to%20it%20and%20read%20the%20error.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Adding%20and%20changing%20keys%0A%0A%20%20%20%20Assigning%20to%20a%20key%20that%20exists%20replaces%20its%20value.%20Assigning%20to%20one%20that%20does%20not%20adds%0A%20%20%20%20it.%20Dictionaries%20change%20in%20place%2C%20the%20same%20way%20lists%20do%2C%20so%20a%20copy%20is%20a%20real%20decision.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(order_10248)%3A%0A%20%20%20%20order_10248_edited%20%3D%20dict(order_10248)%0A%20%20%20%20order_10248_edited%5B%22freight%22%5D%20%3D%2018.00%0A%20%20%20%20order_10248_edited%5B%22carrier%22%5D%20%3D%20%22Speedy%20Express%22%0A%0A%20%20%20%20len(order_10248)%2C%20len(order_10248_edited)%2C%20%22carrier%22%20in%20order_10248%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Five%20keys%20became%20six%2C%20and%20the%20original%20still%20has%20five%20because%20%60dict(...)%60%20made%20a%20second%0A%20%20%20%20dictionary.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20drop%20the%20%60dict(...)%60%20and%20assign%20%60order_10248_edited%20%3D%20order_10248%60%0A%20%20%20%20instead.%20Then%20check%20%60len(order_10248)%60%20again.%20%C2%A711%20already%20told%20you%20what%20happens.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20%60.items()%60%20loops%20over%20both%20halves%0A%0A%20%20%20%20A%20%60for%60%20over%20a%20dictionary%20alone%20gives%20you%20the%20keys.%20%60.items()%60%20gives%20you%20the%20key%20and%20the%0A%20%20%20%20value%20together%2C%20which%20is%20what%20you%20want%20nine%20times%20out%20of%20ten.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(order_10248)%3A%0A%20%20%20%20for%20field_name%2C%20field_value%20in%20order_10248.items()%3A%0A%20%20%20%20%20%20%20%20print(f%22%7Bfield_name%3A%3C14%7D%20%7Bfield_value%7D%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20print%20the%20freight%20totals%20from%20%C2%A713%20the%20same%20way%2C%20sorted%20by%20the%20country%0A%20%20%20%20name.%20%60sorted(freight_by_country.items())%60%20is%20the%20whole%20change.%0A%0A%20%20%20%20%23%23%23%20%E2%9C%94%20Check%20your%20understanding%0A%0A%20%20%20%201.%20%60len()%60%20on%20a%20dictionary%20of%20five%20fields%20returns%205.%20Five%20of%20what%3F%0A%20%20%20%202.%20%60order.get(%22discount%22%2C%200)%60%20never%20raises.%20Give%20a%20case%20where%20that%20is%20exactly%20the%0A%20%20%20%20%20%20%20problem.%0A%20%20%20%203.%20You%20loop%20%60for%20x%20in%20some_dict%3A%60%20and%20print%20%60x%60.%20What%20are%20you%20printing%2C%20and%20what%20would%0A%20%20%20%20%20%20%20you%20write%20to%20get%20the%20values%20instead%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%20%20%20%20%23%23%2016.%20A%20list%20of%20dicts%20is%20a%20table%0A%0A%20%20%20%20One%20dictionary%20is%20one%20row.%20A%20list%20of%20them%20is%20a%20table.%20That%20sentence%20is%20the%20spine%20of%20this%0A%20%20%20%20chapter%20and%20of%20the%20whole%20course%2C%20because%20it%20is%20the%20same%20object%20SQL%20queries%20and%20the%20same%0A%20%20%20%20object%20polars%20loads%2C%20and%20every%20one%20of%20the%20three%20calls%20it%20something%20different.%0A%0A%20%20%20%20%C2%A713%20already%20looped%20over%20five%20orders%20shaped%20this%20way.%20This%20section%20is%20what%20that%20shape%20is.%0A%0A%20%20%20%20%F0%9F%93%96%20**Used%20in%3A**%20What%20one%20row%20means%20%C2%B7%20Choosing%20a%20data%20structure%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20A%20dict%20as%20a%20row%0A%0A%20%20%20%20The%20three%20lines%20of%20order%20%6010248%60%2C%20exactly%20as%20the%20warehouse%20holds%20them.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20order_lines%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%7B%22product%22%3A%20%22Queso%20Cabrales%22%2C%20%22category%22%3A%20%22Dairy%20Products%22%2C%20%22quantity%22%3A%2012%2C%20%22unit_price%22%3A%2014.00%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22product%22%3A%20%22Mozzarella%20di%20Giovanni%22%2C%20%22category%22%3A%20%22Dairy%20Products%22%2C%20%22quantity%22%3A%205%2C%20%22unit_price%22%3A%2034.80%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22product%22%3A%20%22Singaporean%20Hokkien%20Fried%20Mee%22%2C%20%22category%22%3A%20%22Grains%2FCereals%22%2C%20%22quantity%22%3A%2010%2C%20%22unit_price%22%3A%209.80%7D%2C%0A%20%20%20%20%5D%0A%0A%20%20%20%20len(order_lines)%2C%20list(order_lines%5B0%5D.keys())%0A%20%20%20%20return%20(order_lines%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Three%20rows%20and%20four%20columns.%20The%20keys%20of%20the%20first%20row%20*are*%20the%20column%20headers%2C%20which%0A%20%20%20%20is%20why%20%60list(order_lines%5B0%5D.keys())%60%20is%20the%20closest%20thing%20this%20shape%20has%20to%20a%20header%0A%20%20%20%20row.%0A%0A%20%20%20%20**The%20trap.**%20Nothing%20forces%20the%20rows%20to%20agree.%20A%20fourth%20row%20missing%20%60unit_price%60%20is%20a%0A%20%20%20%20legal%20list%20of%20dicts%20and%20an%20illegal%20table%2C%20and%20you%20find%20out%20when%20something%20reads%20that%0A%20%20%20%20key.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20add%20a%20fourth%20line%20with%20only%20%60product%60%20and%20%60quantity%60%20in%20it.%20Then%20run%0A%20%20%20%20%60list(order_lines%5B3%5D.keys())%60%20and%20compare%20it%20to%20row%200.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Building%20the%20table%20row%20by%20row%0A%0A%20%20%20%20A%20literal%20is%20fine%20when%20you%20type%20the%20data%20yourself.%20Everything%20else%20arrives%20one%20row%20at%20a%0A%20%20%20%20time%2C%20so%20the%20shape%20you%20will%20actually%20write%20is%20an%20empty%20list%20and%20an%20%60append%60%20per%20row.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20built_lines%20%3D%20%5B%5D%0A%20%20%20%20built_lines.append(%7B%22product%22%3A%20%22Queso%20Cabrales%22%2C%20%22quantity%22%3A%2012%2C%20%22unit_price%22%3A%2014.00%7D)%0A%20%20%20%20built_lines.append(%7B%22product%22%3A%20%22Mozzarella%20di%20Giovanni%22%2C%20%22quantity%22%3A%205%2C%20%22unit_price%22%3A%2034.80%7D)%0A%20%20%20%20built_lines.append(%7B%22product%22%3A%20%22Singaporean%20Hokkien%20Fried%20Mee%22%2C%20%22quantity%22%3A%2010%2C%20%22unit_price%22%3A%209.80%7D)%0A%0A%20%20%20%20len(built_lines)%2C%20built_lines%5B2%5D%5B%22product%22%5D%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20wrap%20those%20three%20appends%20in%20a%20loop%20over%20a%20list%20of%20three%20tuples%2C%20so%20the%0A%20%20%20%20dictionary%20is%20built%20inside%20the%20loop.%20That%20is%20what%20chapter%20C's%20CSV%20reader%20does%20to%20every%0A%20%20%20%20line%20of%20a%20file.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Totaling%20a%20column%0A%0A%20%20%20%20A%20loop%20over%20the%20rows%2C%20reading%20one%20key%20out%20of%20each.%20Order%20%6010248%60%20before%20freight%20is%20440%2C%0A%20%20%20%20and%20the%20freight%20on%20it%20is%2016.75.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(order_lines)%3A%0A%20%20%20%20subtotal%20%3D%200.0%0A%0A%20%20%20%20for%20priced_line%20in%20order_lines%3A%0A%20%20%20%20%20%20%20%20subtotal%20%3D%20subtotal%20%2B%20priced_line%5B%22quantity%22%5D%20*%20priced_line%5B%22unit_price%22%5D%0A%0A%20%20%20%20subtotal%2C%20f%22%24%7Bsubtotal%3A%2C.2f%7D%22%2C%20f%22%24%7Bsubtotal%20%2B%2016.75%3A%2C.2f%7D%22%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20440.0%20as%20a%20number%2C%20%60%24440.00%60%20as%20a%20sentence%2C%20and%20%60%24456.75%60%20with%20freight%20added.%20The%20three%0A%20%20%20%20line%20amounts%20are%20168.0%2C%20174.0%20and%2098.0%2C%20and%20they%20are%20worth%20adding%20up%20on%20paper%20once.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20total%20the%20%60quantity%60%20column%20instead%2C%20then%20compute%20the%20average%20unit%20price.%0A%20%20%20%20Judge%20whether%20that%20average%20is%20a%20number%20you%20would%20put%20in%20front%20of%20anybody.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Sorting%20the%20rows%20by%20a%20field%0A%0A%20%20%20%20%60sorted()%60%20on%20a%20list%20of%20dicts%20has%20no%20idea%20which%20field%20to%20order%20by%2C%20so%20you%20tell%20it.%0A%20%20%20%20%60key%3D%60%20takes%20a%20function%20that%20is%20handed%20one%20row%20and%20returns%20the%20thing%20to%20sort%20on%2C%20and%0A%20%20%20%20%60lambda%20row%3A%20...%60%20is%20how%20that%20function%20gets%20written%20inline.%20%60reverse%3DTrue%60%20makes%20it%0A%20%20%20%20descending.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(order_lines)%3A%0A%20%20%20%20by_line_total%20%3D%20sorted(order_lines%2C%20key%3Dlambda%20row%3A%20row%5B%22quantity%22%5D%20*%20row%5B%22unit_price%22%5D%2C%20reverse%3DTrue)%0A%0A%20%20%20%20by_line_total%5B0%5D%5B%22product%22%5D%2C%20by_line_total%5B1%5D%5B%22product%22%5D%2C%20by_line_total%5B2%5D%5B%22product%22%5D%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Mozzarella%20at%20174.0%20outranks%20Queso%20at%20168.0%2C%20even%20though%20Queso%20is%2012%20units%20against%205.%0A%20%20%20%20Sorting%20by%20%60quantity%60%20would%20have%20put%20them%20the%20other%20way%20round%2C%20and%20both%20orderings%20are%0A%20%20%20%20correct%20answers%20to%20different%20questions.%0A%0A%20%20%20%20%60%60%60sql%0A%20%20%20%20SELECT%20%22ProductID%22%2C%20%22Quantity%22%20*%20%22UnitPrice%22%20AS%20line_total%0A%20%20%20%20FROM%20%22Order%20Details%22%0A%20%20%20%20WHERE%20%22OrderID%22%20%3D%2010248%0A%20%20%20%20ORDER%20BY%20line_total%20DESC%3B%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20That%20is%20the%20same%20three%20rows%20in%20the%20same%20order%2C%20named%20by%20%60ProductID%60%20because%20the%20names%0A%20%20%20%20live%20in%20another%20table.%20%60ORDER%20BY%20...%20DESC%60%20is%20%60key%3D%60%20plus%0A%20%20%20%20%60reverse%3DTrue%60%2C%20and%20%60SELECT%60%20is%20the%20key%20you%20read%20out%20of%20each%20row.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20sort%20by%20%60category%60%20and%20then%20by%20%60quantity%60%20descending%2C%20in%20one%20call.%0A%20%20%20%20A%20%60key%3D%60%20that%20returns%20a%20tuple%20is%20how%2C%20and%20%C2%A714%20says%20why%20a%20tuple.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Adding%20a%20computed%20column%20without%20touching%20the%20original%0A%0A%20%20%20%20%60%7B**row%2C%20%22new_key%22%3A%20value%7D%60%20makes%20a%20new%20dictionary%20holding%20everything%20the%20old%20one%20had%0A%20%20%20%20plus%20one%20more%20field.%20Build%20a%20new%20list%20out%20of%20those%20and%20the%20source%20rows%20are%20untouched.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(order_lines)%3A%0A%20%20%20%20lines_with_total%20%3D%20%5B%5D%0A%0A%20%20%20%20for%20source_line%20in%20order_lines%3A%0A%20%20%20%20%20%20%20%20lines_with_total.append(%7B**source_line%2C%20%22line_total%22%3A%20source_line%5B%22quantity%22%5D%20*%20source_line%5B%22unit_price%22%5D%7D)%0A%0A%20%20%20%20len(lines_with_total%5B0%5D)%2C%20len(order_lines%5B0%5D)%2C%20lines_with_total%5B0%5D%5B%22line_total%22%5D%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Five%20keys%20in%20the%20new%20row%2C%20four%20in%20the%20original%2C%20and%20the%20first%20line%20total%20is%20168.0.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20add%20a%20second%20computed%20column%20in%20the%20same%20pass%2C%20%60%22is_dairy%22%60%2C%20from%20the%0A%20%20%20%20%60category%60%20field.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Copying%20the%20list%20does%20not%20copy%20the%20rows%0A%0A%20%20%20%20%C2%A711%20said%20%60.copy()%60%20gives%20you%20a%20second%20list.%20It%20does.%20What%20it%20does%20not%20do%20is%20give%20you%0A%20%20%20%20second%20dictionaries%3A%20both%20lists%20hold%20the%20*same*%20rows%2C%20so%20editing%20a%20row%20through%20either%0A%20%20%20%20list%20changes%20it%20for%20both.%20That%20is%20a%20**shallow%20copy**%2C%20and%20%60copy.deepcopy()%60%20is%20the%0A%20%20%20%20**deep%20copy**%20that%20goes%20all%20the%20way%20down.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20copy%0A%0A%20%20%20%20two_lines%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%7B%22product%22%3A%20%22Queso%20Cabrales%22%2C%20%22quantity%22%3A%2012%7D%2C%0A%20%20%20%20%20%20%20%20%7B%22product%22%3A%20%22Mozzarella%20di%20Giovanni%22%2C%20%22quantity%22%3A%205%7D%2C%0A%20%20%20%20%5D%0A%20%20%20%20shallow_copy%20%3D%20two_lines.copy()%0A%20%20%20%20deep_copy%20%3D%20copy.deepcopy(two_lines)%0A%0A%20%20%20%20shallow_copy%5B0%5D%5B%22quantity%22%5D%20%3D%2099%0A%20%20%20%20deep_copy%5B1%5D%5B%22quantity%22%5D%20%3D%2055%0A%0A%20%20%20%20two_lines%2C%20deep_copy%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Read%20the%20two%20outputs%20side%20by%20side.%20The%2099%20written%20through%20%60shallow_copy%60%20is%20sitting%20in%0A%20%20%20%20%60two_lines%60.%20The%2055%20written%20through%20%60deep_copy%60%20is%20not.%0A%0A%20%20%20%20**The%20trap%2C%20and%20it%20is%20the%20one%20that%20bites%20this%20shape%20hardest.**%20Cleaning%20a%20copy%20of%20your%0A%20%20%20%20data%20is%20the%20reason%20anybody%20copies%20it%2C%20and%20%60.copy()%60%20on%20a%20list%20of%20dicts%20is%20the%20version%20of%0A%20%20%20%20that%20which%20quietly%20edits%20the%20original.%20Build%20a%20new%20list%20of%20new%20dictionaries%2C%20the%20way%20the%0A%20%20%20%20computed-column%20cell%20above%20does%2C%20or%20reach%20for%20%60copy.deepcopy%60.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20add%20%60shallow_copy%5B0%5D%20%3D%20%7B%22product%22%3A%20%22Something%20else%22%2C%20%22quantity%22%3A%201%7D%60%20to%0A%20%20%20%20that%20cell%20and%20check%20%60two_lines%60%20again.%20Replacing%20a%20whole%20row%20behaves%20differently%20from%0A%20%20%20%20editing%20one%2C%20and%20the%20difference%20is%20the%20point.%0A%0A%20%20%20%20%23%23%23%20%E2%9C%94%20Check%20your%20understanding%0A%0A%20%20%20%201.%20You%20are%20handed%20a%20list%20of%20500%20dictionaries.%20What%20is%20the%20fastest%20way%20to%20find%20out%20what%0A%20%20%20%20%20%20%20the%20columns%20are%2C%20and%20what%20could%20that%20answer%20miss%3F%0A%20%20%20%202.%20%60sorted(rows)%60%20raises%20on%20a%20list%20of%20dicts.%20What%20do%20you%20have%20to%20supply%2C%20and%20what%20is%20it%0A%20%20%20%20%20%20%20for%3F%0A%20%20%20%203.%20You%20copy%20a%20list%20of%20rows%2C%20clean%20the%20copy%2C%20and%20the%20original%20is%20clean%20too.%20What%0A%20%20%20%20%20%20%20happened%2C%20and%20what%20would%20you%20have%20written%20instead%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%20%20%20%20%23%23%2017.%20Sets%0A%0A%20%20%20%20A%20set%20holds%20each%20value%20once%20and%20keeps%20no%20order.%20It%20answers%20two%20questions%20faster%20and%20more%0A%20%20%20%20clearly%20than%20a%20list%20does%3A%20what%20are%20the%20distinct%20values%2C%20and%20have%20I%20seen%20this%20one%20before.%0A%0A%20%20%20%20%F0%9F%93%96%20**Used%20in%3A**%20Choosing%20a%20data%20structure%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Unique%20values%20without%20positions%0A%0A%20%20%20%20Five%20orders%20shipped%20to%20four%20countries%2C%20because%20France%20appears%20twice.%20%60set()%60%20is%20how%20you%0A%20%20%20%20express%20that%20in%20one%20line.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(ship_countries)%3A%0A%20%20%20%20distinct_countries%20%3D%20set(ship_countries)%0A%0A%20%20%20%20len(ship_countries)%2C%20len(distinct_countries)%2C%20sorted(distinct_countries)%0A%20%20%20%20return%20(distinct_countries%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20The%20%60sorted()%60%20is%20there%20for%20a%20reason.%20A%20set%20prints%20in%20whatever%20order%20it%20happens%20to%20hold%0A%20%20%20%20its%20values%2C%20and%20that%20order%20can%20differ%20between%20runs%2C%20so%20anything%20you%20show%20a%20person%20goes%0A%20%20%20%20through%20%60sorted()%60%20first.%0A%0A%20%20%20%20**The%20trap.**%20A%20set%20has%20values%20and%20no%20positions%3A%0A%0A%20%20%20%20%60%60%60python%0A%20%20%20%20distinct_countries%5B0%5D%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20%60%60%60%0A%20%20%20%20TypeError%3A%20'set'%20object%20is%20not%20subscriptable%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20build%20a%20set%20from%20the%20freight%20charges%20and%20count%20it.%20Then%20add%20a%20duplicate%0A%20%20%20%20charge%20to%20the%20list%20and%20count%20both%20again.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20%60in%60%20is%20what%20a%20set%20is%20fast%20at%0A%0A%20%20%20%20%60in%60%20works%20on%20a%20list%20too.%20On%20a%20set%20it%20stays%20fast%20no%20matter%20how%20many%20values%20are%20in%20it%2C%0A%20%20%20%20which%20is%20why%20a%20membership%20test%20over%20a%20large%20reference%20list%20belongs%20in%20a%20set.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(distinct_countries)%3A%0A%20%20%20%20%22France%22%20in%20distinct_countries%2C%20%22Spain%22%20in%20distinct_countries%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20put%20the%20four%20country%20names%20in%20a%20list%20and%20run%20the%20same%20two%20tests.%20The%0A%20%20%20%20answers%20match%2C%20and%20for%20four%20values%20the%20speed%20does%20too.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Comparing%20sets%0A%0A%20%20%20%20%60%26%60%20keeps%20what%20is%20in%20both%2C%20%60-%60%20keeps%20what%20is%20only%20in%20the%20first%2C%20and%20%60%7C%60%20keeps%20everything%0A%20%20%20%20from%20either.%20The%20countries%20of%20the%20first%20three%20orders%20against%20the%20last%20three.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20first_three_countries%20%3D%20%7B%22France%22%2C%20%22Germany%22%2C%20%22Brazil%22%7D%0A%20%20%20%20last_three_countries%20%3D%20%7B%22Brazil%22%2C%20%22France%22%2C%20%22Belgium%22%7D%0A%0A%20%20%20%20(%0A%20%20%20%20%20%20%20%20sorted(first_three_countries%20%26%20last_three_countries)%2C%0A%20%20%20%20%20%20%20%20sorted(first_three_countries%20-%20last_three_countries)%2C%0A%20%20%20%20%20%20%20%20sorted(first_three_countries%20%7C%20last_three_countries)%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Brazil%20and%20France%20are%20in%20both%20windows%2C%20Germany%20is%20only%20in%20the%20first%2C%20and%20four%20countries%0A%20%20%20%20appear%20across%20the%20week.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20run%20%60last_three_countries%20-%20first_three_countries%60%20and%20confirm%20it%20gives%20a%0A%20%20%20%20different%20answer%20from%20the%20one%20above.%20Subtraction%20has%20a%20direction%20and%20intersection%20does%0A%20%20%20%20not.%0A%0A%20%20%20%20%23%23%23%20%E2%9C%94%20Check%20your%20understanding%0A%0A%20%20%20%201.%20A%20list%20of%2010%2C000%20order%20countries%20becomes%20a%20set%20of%2021.%20What%20did%20you%20learn%2C%20and%20what%0A%20%20%20%20%20%20%20did%20you%20lose%3F%0A%20%20%20%202.%20You%20need%20to%20know%20which%20products%20were%20ordered%20in%20July%20and%20not%20in%20August.%20Which%20set%0A%20%20%20%20%20%20%20operation%2C%20and%20in%20which%20direction%3F%0A%20%20%20%203.%20Why%20does%20this%20section%20put%20%60sorted()%60%20around%20every%20set%20it%20displays%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%20%20%20%20%23%23%2018.%20Comprehensions%0A%0A%20%20%20%20%3E%20**Advanced**%0A%0A%20%20%20%20A%20comprehension%20builds%20a%20list%20in%20one%20line%20out%20of%20another%20list.%20You%20are%20here%20to%20**read**%0A%20%20%20%20them%3A%20an%20agent%20asked%20for%20anything%20in%20this%20chapter%20will%20write%20one%2C%20and%20the%20code%20you%20are%0A%20%20%20%20checking%20will%20be%20full%20of%20them%20long%20before%20you%20choose%20to%20write%20your%20own.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Comprehensions%20as%20loops%0A%0A%20%20%20%20Transform%20every%20row.%20Keep%20some%20rows.%20Do%20both.%20The%20%60for%60%20is%20in%20the%20middle%20of%20the%20line%2C%0A%20%20%20%20the%20thing%20being%20collected%20is%20at%20the%20front%2C%20and%20the%20condition%20is%20at%20the%20end.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(order_lines)%3A%0A%20%20%20%20product_names%20%3D%20%5Bline%5B%22product%22%5D%20for%20line%20in%20order_lines%5D%0A%20%20%20%20dairy_lines%20%3D%20%5Bline%20for%20line%20in%20order_lines%20if%20line%5B%22category%22%5D%20%3D%3D%20%22Dairy%20Products%22%5D%0A%20%20%20%20dairy_names%20%3D%20%5Bline%5B%22product%22%5D%20for%20line%20in%20order_lines%20if%20line%5B%22category%22%5D%20%3D%3D%20%22Dairy%20Products%22%5D%0A%0A%20%20%20%20product_names%2C%20len(dairy_lines)%2C%20dairy_names%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Three%20products%2C%20two%20of%20them%20dairy.%20The%20second%20form%20keeps%20whole%20rows%20and%20the%20third%20keeps%0A%20%20%20%20one%20field%20out%20of%20the%20rows%20it%20kept%2C%20which%20is%20the%20difference%20between%20%60SELECT%20*%60%20and%0A%20%20%20%20%60SELECT%20ProductName%60.%0A%0A%20%20%20%20**How%20to%20read%20one.**%20Find%20the%20%60for%60%20first%20and%20read%20the%20middle.%20That%20tells%20you%20what%20is%0A%20%20%20%20being%20looped%20over.%20Then%20read%20the%20end%2C%20which%20is%20the%20filter.%20Then%20read%20the%20front%2C%20which%20is%0A%20%20%20%20what%20comes%20out.%20Front%2C%20middle%2C%20end%20is%20the%20order%20it%20is%20written%20in%20and%20the%20wrong%20order%20to%0A%20%20%20%20read%20it%20in.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20write%20the%20first%20line%20as%20a%20four-line%20%60for%60%20loop%20with%20an%20%60append%60.%20Then%20decide%0A%20%20%20%20which%20of%20the%20two%20you%20would%20rather%20find%20in%20code%20somebody%20else%20wrote.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20A%20comprehension%20builds%20a%20new%20list%20and%20changes%20nothing%0A%0A%20%20%20%20Whatever%20it%20was%20reading%20is%20exactly%20as%20it%20was%20afterward.%20That%20is%20worth%20knowing%20when%20you%0A%20%20%20%20are%20auditing%20agent%20output%2C%20because%20it%20means%20a%20comprehension%20is%20never%20the%20line%20that%0A%20%20%20%20edited%20your%20data.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(order_lines)%3A%0A%20%20%20%20quantity_by_product%20%3D%20%7Bline%5B%22product%22%5D%3A%20line%5B%22quantity%22%5D%20for%20line%20in%20order_lines%7D%0A%0A%20%20%20%20quantity_by_product%2C%20len(order_lines)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Braces%20instead%20of%20brackets%2C%20and%20a%20%60key%3A%20value%60%20in%20front%2C%20and%20you%20get%20a%20dictionary%0A%20%20%20%20instead%20of%20a%20list.%20Indexing%20a%20table%20by%20one%20of%20its%20fields%20is%20what%20this%20form%20is%20usually%0A%20%20%20%20doing.%0A%0A%20%20%20%20**The%20trap.**%20A%20dictionary%20keeps%20one%20value%20per%20key.%20If%20two%20rows%20share%20a%20product%20name%2C%0A%20%20%20%20the%20second%20one%20silently%20replaces%20the%20first%20and%20the%20count%20drops%20with%20no%20warning.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20add%20a%20fourth%20line%20to%20%60order_lines%60%20with%20%60%22product%22%3A%20%22Queso%20Cabrales%22%60%20and%0A%20%20%20%20a%20different%20quantity.%20Then%20check%20%60len(quantity_by_product)%60%20against%20%60len(order_lines)%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20When%20to%20write%20the%20loop%20instead%0A%0A%20%20%20%20A%20comprehension%20that%20carries%20two%20conditions%2C%20a%20nested%20%60for%60%20and%20a%20calculation%20is%20a%0A%20%20%20%20sentence%20with%20no%20punctuation.%20The%20loop%20version%20is%20longer%2C%20and%20the%20reason%20to%20prefer%20it%20is%0A%20%20%20%20that%20you%20can%20put%20a%20%60print%60%20in%20the%20middle%20of%20a%20loop%20and%20cannot%20put%20one%20in%20the%20middle%20of%20a%0A%20%20%20%20comprehension.%0A%0A%20%20%20%20That%20is%20also%20the%20honest%20test%20for%20agent-written%20code.%20If%20you%20cannot%20explain%20out%20loud%20what%20a%0A%20%20%20%20comprehension%20collects%2C%20ask%20for%20it%20as%20a%20loop%20and%20read%20that.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20ask%20an%20agent%20to%20rewrite%20%60dairy_names%60%20as%20a%20plain%20loop%2C%20and%20then%20to%0A%20%20%20%20rewrite%20one%20of%20your%20own%20loops%20as%20a%20comprehension.%20Run%20both%20and%20compare%20the%20answers%2C%20not%0A%20%20%20%20the%20prose.%0A%0A%20%20%20%20%23%23%23%20%E2%9C%94%20Check%20your%20understanding%0A%0A%20%20%20%201.%20%60%5Bo%5B%22freight%22%5D%20for%20o%20in%20orders%20if%20o%5B%22days_to_ship%22%5D%20%3E%207%5D%60%20produces%20what%2C%20and%20how%20many%0A%20%20%20%20%20%20%20items%20does%20it%20have%3F%0A%20%20%20%202.%20Which%20part%20of%20a%20comprehension%20do%20you%20read%20first%2C%20and%20why%20is%20it%20not%20the%20first%20part%0A%20%20%20%20%20%20%20written%3F%0A%20%20%20%203.%20A%20dict%20comprehension%20over%20500%20rows%20gives%20480%20keys.%20What%20happened%20to%20the%20other%2020%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%20%20%20%20%23%23%2019.%20Choosing%20a%20data%20structure%0A%0A%20%20%20%20Five%20shapes%2C%20which%20most%20books%20call%20**data%20structures**%2C%20have%20now%20gone%20past%3A%20list%2C%20tuple%2C%0A%20%20%20%20dictionary%2C%20list%20of%20dicts%2C%20set.%20Choosing%20between%20them%20is%20a%20procedure%20with%20four%0A%20%20%20%20questions%2C%20and%20you%20answer%20them%20in%20order.%0A%0A%20%20%20%20%F0%9F%93%96%20**Used%20in%3A**%20Choosing%20a%20data%20structure%20%C2%B7%20Getting%20data%20from%20an%20API%20%C2%B7%20Designing%20your%20database%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Questions%20for%20choosing%20a%20structure%0A%0A%20%20%20%201.%20**Do%20you%20need%20each%20value%20only%20once%2C%20such%20as%20the%20distinct%20countries%2C%20or%20every%0A%20%20%20%20%20%20%20customer%20counted%20once%3F**%20Then%20it%20is%20a%20**set**%2C%20and%20nothing%20else%20in%20the%20list%20applies.%0A%20%20%20%202.%20**Is%20this%20one%20thing%20with%20named%20parts%3F**%20A%20single%20order%2C%20a%20single%20customer%2C%20a%20single%0A%20%20%20%20%20%20%20configuration.%20Then%20it%20is%20a%20**dictionary**%2C%20with%20the%20part%20names%20as%20keys.%20If%20the%20parts%0A%20%20%20%20%20%20%20are%20fixed%20and%20must%20never%20change%2C%20and%20especially%20if%20this%20is%20going%20to%20be%20a%20dictionary%0A%20%20%20%20%20%20%20key%2C%20it%20is%20a%20**tuple**%20instead.%0A%20%20%20%203.%20**Is%20it%20many%20of%20the%20same%20thing%3F**%20Then%20it%20is%20a%20**list**.%20The%20next%20question%20decides%0A%20%20%20%20%20%20%20what%20is%20inside%20it.%0A%20%20%20%204.%20**Does%20each%20of%20those%20things%20have%20named%20parts%3F**%20Yes%20gives%20you%20a%20**list%20of%0A%20%20%20%20%20%20%20dictionaries**%2C%20which%20is%20a%20table%20and%20is%20the%20right%20answer%20most%20of%20the%20time%20in%20this%0A%20%20%20%20%20%20%20course.%20No%20gives%20you%20a%20plain%20list%20of%20values%2C%20which%20is%20right%20when%20there%20is%20genuinely%0A%20%20%20%20%20%20%20only%20one%20number%20per%20item.%0A%0A%20%20%20%20The%20order%20matters%2C%20because%20question%204%20is%20the%20one%20people%20skip.%20A%20list%20of%20values%20is%20easy%0A%20%20%20%20to%20type%20and%20stops%20being%20enough%20the%20moment%20somebody%20asks%20*which%20country*.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20The%20shape%20that%20looks%20fine%20and%20is%20not%0A%0A%20%20%20%20Two%20lists%20side%20by%20side%2C%20one%20holding%20countries%20and%20one%20holding%20freight%2C%20with%20position%200%0A%20%20%20%20of%20each%20belonging%20to%20the%20same%20order.%20It%20works%2C%20right%20up%20until%20something%20reorders%20one%20of%0A%20%20%20%20them.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20parallel_countries%20%3D%20%5B%22France%22%2C%20%22Germany%22%2C%20%22Brazil%22%2C%20%22France%22%2C%20%22Belgium%22%5D%0A%20%20%20%20parallel_freight%20%3D%20%5B16.75%2C%2022.25%2C%2025.00%2C%2020.25%2C%2036.25%5D%0A%0A%20%20%20%20before_sort%20%3D%20list(zip(parallel_countries%2C%20parallel_freight))%0A%20%20%20%20parallel_freight.sort()%0A%20%20%20%20after_sort%20%3D%20list(zip(parallel_countries%2C%20parallel_freight))%0A%0A%20%20%20%20before_sort%2C%20after_sort%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%60zip%60%20pairs%20the%20two%20lists%20by%20position%2C%20which%20is%20the%20pairing%20the%20whole%20arrangement%0A%20%20%20%20depends%20on.%20Read%20the%20two%20outputs%20against%20each%20other.%20Before%20the%20sort%2C%20Germany%20owes%2022.25%0A%20%20%20%20and%20Brazil%20owes%2025.0.%20After%20it%2C%20Germany%20owes%2020.25%20and%20Brazil%20owes%2022.25.%20Three%20of%20the%0A%20%20%20%20five%20rows%20are%20now%20wrong%2C%20every%20number%20is%20still%20a%20real%20freight%20charge%2C%20and%20nothing%0A%20%20%20%20raised.%0A%0A%20%20%20%20**The%20two%20that%20survived%20are%20the%20reason%20this%20hides.**%20France%20keeps%2016.75%20and%20Belgium%0A%20%20%20%20keeps%2036.25%2C%20because%20those%20are%20the%20smallest%20and%20largest%20charges%20and%20the%20sort%20left%20them%0A%20%20%20%20where%20they%20were.%20Spot-check%20the%20first%20row%20and%20the%20last%20row%20and%20the%20data%20looks%20fine.%0A%0A%20%20%20%20A%20list%20of%20dictionaries%20cannot%20do%20this%20to%20you%2C%20because%20the%20country%20and%20the%20charge%20are%20in%0A%20%20%20%20the%20same%20row%20and%20sorting%20moves%20them%20together.%20That%20is%20most%20of%20the%20argument%20for%20%C2%A716.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20rebuild%20those%20five%20orders%20as%20a%20list%20of%20dicts%2C%20sort%20it%20by%20freight%2C%20and%0A%20%20%20%20confirm%20the%20countries%20follow%20their%20charges.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20The%20procedure%20on%20a%20real%20question%0A%0A%20%20%20%20*%22Which%20country%20cost%20us%20the%20most%20in%20freight%20last%20week%3F%22*%0A%0A%20%20%20%20Question%201%3A%20no%2C%20you%20are%20not%20testing%20membership.%20Question%202%3A%20no%2C%20this%20is%20five%20orders%20and%0A%20%20%20%20not%20one.%20Question%203%3A%20yes%2C%20many%20of%20the%20same%20thing%2C%20so%20a%20list.%20Question%204%3A%20each%20order%20has%0A%20%20%20%20an%20id%2C%20a%20country%2C%20a%20freight%20charge%20and%20a%20shipping%20time%2C%20so%20a%20**list%20of%20dictionaries**.%0A%0A%20%20%20%20Then%20the%20answer%20itself%20is%20a%20country%20and%20a%20number%20per%20country%2C%20which%20is%20one%20thing%20with%0A%20%20%20%20named%20parts%20repeated%2C%20so%20it%20comes%20out%20as%20a%20**dictionary**%20keyed%20by%20country.%20That%20is%0A%20%20%20%20exactly%20what%20%C2%A713%20built.%0A%0A%20%20%20%20A%20shape%20is%20a%20bet%20about%20the%20questions%20you%20will%20be%20asked%20next.%20Getting%20it%20wrong%20is%0A%20%20%20%20recoverable%20and%20rewriting%20the%20analysis%20around%20it%20is%20what%20costs%20the%20afternoon.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20run%20the%20same%20four%20questions%20over%20*%22how%20many%20distinct%20products%20did%20we%20sell%0A%20%20%20%20in%20July%22*%20and%20over%20*%22what%20is%20our%20current%20exchange%20rate%22*.%20Two%20questions%2C%20two%20different%0A%20%20%20%20shapes%2C%20and%20neither%20is%20a%20list%20of%20dicts.%0A%0A%20%20%20%20%23%23%23%20%E2%9C%94%20Check%20your%20understanding%0A%0A%20%20%20%201.%20You%20have%20five%20orders%20and%20one%20freight%20charge%20each.%20Name%20two%20shapes%20that%20hold%20that%2C%20and%0A%20%20%20%20%20%20%20explain%20what%20the%20second%20one%20lets%20you%20ask%20that%20the%20first%20does%20not.%0A%20%20%20%202.%20Somebody%20hands%20you%20two%20lists%20that%20line%20up%20by%20position.%20What%20is%20the%20first%20question%20you%0A%20%20%20%20%20%20%20ask%20them%3F%0A%20%20%20%203.%20Question%204%20in%20the%20procedure%20asks%20whether%20each%20item%20has%20named%20parts.%20Give%20an%20example%0A%20%20%20%20%20%20%20from%20your%20own%20work%20where%20the%20answer%20is%20no.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%20%20%20%20%23%23%20Chapter%20challenge%0A%0A%20%20%20%20**The%20first%20week%20of%20orders.**%20Nothing%20here%20is%20due.%20It%20exists%20because%20the%20sections%20above%20each%20teach%20one%20thing%20and%20one%0A%20%20%20%20real%20question%20needs%20most%20of%20them%20at%20once.%0A%0A%20%20%20%20%7C%20OrderID%20%7C%20ship%20country%20%7C%20freight%20%7C%20days%20to%20ship%20%7C%0A%20%20%20%20%7C---%7C---%7C---%7C---%7C%0A%20%20%20%20%7C%2010248%20%7C%20France%20%7C%2016.75%20%7C%2012%20%7C%0A%20%20%20%20%7C%2010249%20%7C%20Germany%20%7C%2022.25%20%7C%205%20%7C%0A%20%20%20%20%7C%2010250%20%7C%20Brazil%20%7C%2025.00%20%7C%204%20%7C%0A%20%20%20%20%7C%2010251%20%7C%20France%20%7C%2020.25%20%7C%207%20%7C%0A%20%20%20%20%7C%2010252%20%7C%20Belgium%20%7C%2036.25%20%7C%202%20%7C%0A%0A%20%20%20%20**Build%20these%20five%20orders%20as%20one%20collection%20and%20answer%20three%20questions%20from%20it.**%0A%0A%20%20%20%20-%20Which%20country%20cost%20the%20most%20in%20freight%20across%20the%20week%3F%0A%20%20%20%20-%20Which%20order%20took%20longest%20to%20ship%3F%0A%20%20%20%20-%20What%20share%20of%20the%20week's%20orders%20shipped%20in%20under%20a%20week%3F%0A%0A%20%20%20%20**Four%20decisions%20are%20yours%2C%20and%20the%20notebook%20cannot%20make%20them.**%0A%0A%20%20%20%201.%20What%20shape%20holds%20the%20five%20orders%3F%20Name%20it%2C%20and%20state%20one%20thing%20it%20makes%20easy%20and%20one%0A%20%20%20%20%20%20%20thing%20it%20makes%20hard.%0A%20%20%20%202.%20%22Under%20a%20week%22%20is%20how%20many%20days%3F%20Write%20the%20comparison%20you%20mean%20and%20state%20what%20happens%0A%20%20%20%20%20%20%20to%20order%20%6010251%60.%0A%20%20%20%203.%20France%20appears%20twice.%20Does%20the%20answer%20keep%20them%20as%20two%20orders%20or%20as%20one%20country%3F%0A%20%20%20%20%20%20%20Both%20are%20defensible%2C%20so%20state%20which%20question%20you%20are%20answering.%0A%20%20%20%204.%20The%20freight%20values%20carry%20two%20decimals.%20Where%20in%20your%20calculation%20do%20you%20round%2C%20and%0A%20%20%20%20%20%20%20why%20there%3F%0A%0A%20%20%20%20**Done%20looks%20like**%20one%20cell%20producing%20three%20answers%2C%20plus%20a%20markdown%20cell%20naming%20the%0A%20%20%20%20four%20decisions%20and%20what%20the%20alternative%20would%20have%20been.%0A%0A%20%20%20%20**Going%20further.**%20Give%20order%20%6010248%60%20its%20three%20line%20items%2C%20so%20one%20record%20carries%20a%20list%0A%20%20%20%20of%20dictionaries%20inside%20it%2C%20and%20compute%20the%20order%20total%20with%20freight.%20Then%20make%20your%20code%0A%20%20%20%20survive%20an%20order%20whose%20line%20items%20are%20missing%20entirely.%20Then%20add%20a%20sixth%20order%20with%20the%0A%20%20%20%20country%20typed%20as%20%60%22france%22%60%20and%20decide%20what%20should%20happen%2C%20in%20code%20and%20not%20by%0A%20%20%20%20editing%20the%20data.%20Then%20hand%20the%20notebook%20to%20somebody%20outside%20this%20course%20and%20write%20down%0A%20%20%20%20the%20first%20question%20they%20ask.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%20%20%20%20%23%23%20%F0%9F%A4%96%20Ask%20your%20agent%0A%0A%20%20%20%20Two%20different%20uses%2C%20and%20the%20second%20one%20is%20the%20one%20this%20course%20grades.%0A%0A%20%20%20%20%23%23%23%20Ask%20it%20about%20what%20this%20chapter%20left%20out%0A%0A%20%20%20%20Every%20one%20of%20these%20is%20real%20Python%20that%20had%20no%20room%20above.%0A%0A%20%20%20%20-%20%60collections.Counter%60%20does%20%C2%A713's%20counting%20loop%20in%20one%20line.%20Ask%20what%20it%20gives%20back%2C%0A%20%20%20%20%20%20and%20whether%20that%20thing%20is%20a%20dictionary.%0A%20%20%20%20-%20%60dict.setdefault%60%20and%20%60collections.defaultdict%60%20are%20two%20more%20ways%20to%20write%20the%20same%0A%20%20%20%20%20%20accumulator.%20Ask%20which%20one%20an%20agent%20reaches%20for%20by%20default%2C%20and%20why.%0A%20%20%20%20-%20You%20met%20%60zip%60%20once%2C%20in%20%C2%A719.%20Ask%20what%20it%20does%20when%20the%20two%20lists%20are%20different%20lengths%2C%0A%20%20%20%20%20%20and%20whether%20it%20warns%20you.%0A%20%20%20%20-%20%60sorted%60%20accepts%20a%20%60key%60%20that%20returns%20a%20tuple.%20Ask%20how%20to%20sort%20orders%20by%20country%20and%0A%20%20%20%20%20%20then%20by%20freight%20descending%20inside%20each%20country.%0A%20%20%20%20-%20%60any()%60%20and%20%60all()%60%20take%20a%20list%20of%20comparisons.%20Ask%20what%20each%20returns%20for%20an%20empty%0A%20%20%20%20%20%20list%2C%20and%20predict%20it%20before%20you%20read%20the%20answer.%0A%0A%20%20%20%20Test%20whatever%20it%20gives%20you.%20Paste%20it%20into%20a%20cell%20and%20run%20it.%0A%0A%20%20%20%20%23%23%23%20Watch%20what%20it%20decides%20without%20telling%20you%0A%0A%20%20%20%20Give%20it%20this%2C%20exactly%2C%20with%20the%20five%20orders%20pasted%20underneath%3A%0A%0A%20%20%20%20%3E%20*%22Write%20Python%20that%20summarizes%20these%20five%20orders%20by%20country.%22*%0A%0A%20%20%20%20Then%20read%20what%20came%20back%20and%20answer%20four%20questions.%0A%0A%20%20%20%201.%20**What%20shape%20did%20it%20choose%20for%20the%20input%2C%20and%20did%20it%20change%20the%20shape%20you%20gave%20it%3F**%0A%20%20%20%202.%20**Did%20it%20sort%20the%20answer%3F**%20By%20what%2C%20and%20in%20which%20direction%3F%20You%20did%20not%20ask%20for%20a%0A%20%20%20%20%20%20%20sort.%0A%20%20%20%203.%20**What%20does%20it%20do%20with%20%60%22france%22%60%20in%20lowercase%3F**%20Read%20the%20code%20before%20you%20test%20it.%0A%20%20%20%204.%20**Does%20it%20round%2C%20and%20to%20how%20many%20places%3F**%20Find%20the%20line.%0A%0A%20%20%20%20You%20asked%20for%20a%20summary%20and%20got%20four%20or%20five%20decisions.%20That%20gap%20is%20the%20subject%20of%20this%0A%20%20%20%20course%2C%20and%20it%20does%20not%20go%20away%20as%20the%20models%20get%20better.%20It%20gets%20quieter.%0A%0A%20%20%20%20%F0%9F%91%89%20**Try%20it%3A**%20send%20the%20same%20sentence%20twice%2C%20in%20two%20separate%20conversations.%20Compare%20the%0A%20%20%20%20two%20shapes%20it%20chose.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%20%20%20%20%23%23%20Chapter%20B%20checklist%0A%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20build%20a%20list%2C%20count%20it%2C%20and%20take%20one%20item%20or%20a%20slice%20out%20of%20it%0A%20%20%20%20-%20%5B%20%5D%20I%20know%20that%20a%20list%20changes%20in%20place%20and%20a%20string%20does%20not%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20state%20what%20%60sorted()%60%20leaves%20behind%20and%20what%20%60.sort()%60%20leaves%20behind%0A%20%20%20%20-%20%5B%20%5D%20I%20know%20what%20%60x%20%3D%20lst.sort()%60%20puts%20in%20%60x%60%2C%20and%20where%20the%20failure%20shows%20up%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20tell%20two%20names%20for%20one%20list%20from%20two%20separate%20lists%2C%20and%20I%20can%20make%20a%20copy%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20write%20a%20%60for%60%20loop%20over%20a%20list%20and%20choose%20a%20readable%20name%20for%20the%20item%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20build%20a%20running%20total%2C%20and%20I%20know%20why%20the%20zero%20goes%20outside%20the%20loop%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20filter%20inside%20a%20loop%20and%20collect%20what%20passes%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20keep%20a%20count%20and%20a%20total%20in%20one%20pass%20and%20get%20an%20average%20out%20of%20them%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20total%20one%20field%20grouped%20by%20another%2C%20and%20I%20know%20that%20is%20what%20%60GROUP%20BY%60%20does%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20explain%20why%20a%20dictionary%20key%20is%20case-sensitive%20and%20a%20%60SUMIF%60%20criterion%20is%20not%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20make%20a%20tuple%2C%20unpack%20it%2C%20and%20name%20a%20case%20where%20a%20list%20would%20be%20wrong%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20use%20a%20tuple%20as%20a%20dictionary%20key%20and%20explain%20why%20a%20list%20cannot%20be%20one%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20read%20a%20value%20out%20of%20a%20dictionary%20by%20key%20and%20handle%20a%20key%20that%20is%20missing%0A%20%20%20%20-%20%5B%20%5D%20I%20know%20that%20a%20%60.get()%60%20default%20is%20a%20claim%20about%20my%20data%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20loop%20over%20a%20dictionary's%20keys%20and%20values%20together%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20describe%20what%20a%20list%20of%20dictionaries%20is%2C%20and%20where%20the%20column%20headers%20live%20in%20it%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20build%20a%20table%20row%20by%20row%20with%20%60append%60%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20sort%20a%20table%20by%20a%20field%20with%20%60key%3D%60%20and%20%60reverse%3DTrue%60%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20add%20a%20computed%20column%20without%20changing%20the%20original%20rows%0A%20%20%20%20-%20%5B%20%5D%20I%20know%20that%20copying%20a%20list%20of%20dictionaries%20shares%20the%20dictionaries%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20read%20a%20comprehension%20by%20finding%20its%20%60for%60%20first%0A%20%20%20%20-%20%5B%20%5D%20I%20can%20run%20the%20four%20questions%20and%20choose%20a%20shape%20before%20I%20write%20any%20code%0A%0A%20%20%20%20**Chapter%20C%20is%20Data**%3A%20getting%20somebody%20else's%20file%20in%2C%20and%20what%20it%20does%20to%20all%20of%20this%0A%20%20%20%20once%20the%20rows%20are%20real.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
d15b6df5d09d811e5fe43fa4bc31df96