<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=us-ascii"><meta name=Generator content="Microsoft Word 14 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
{font-family:Helvetica;
panose-1:2 11 6 4 2 2 2 2 2 4;}
@font-face
{font-family:Wingdings;
panose-1:5 0 0 0 0 0 0 0 0 0;}
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
{font-family:Tahoma;
panose-1:2 11 6 4 3 5 4 4 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0mm;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-fareast-language:EN-US;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:#0563C1;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:#954F72;
text-decoration:underline;}
p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph
{mso-style-priority:34;
margin-top:0mm;
margin-right:0mm;
margin-bottom:0mm;
margin-left:36.0pt;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-fareast-language:EN-US;}
span.EmailStyle17
{mso-style-type:personal;
font-family:"Calibri","sans-serif";
color:windowtext;}
span.EmailStyle18
{mso-style-type:personal-reply;
font-family:"Calibri","sans-serif";
color:#44546A;}
.MsoChpDefault
{mso-style-type:export-only;
font-size:10.0pt;}
@page WordSection1
{size:612.0pt 792.0pt;
margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
{page:WordSection1;}
/* List Definitions */
@list l0
{mso-list-id:1453591379;
mso-list-type:hybrid;
mso-list-template-ids:1279698092 134807553 134807555 134807557 134807553 134807555 134807557 134807553 134807555 134807557;}
@list l0:level1
{mso-level-number-format:bullet;
mso-level-text:\F0B7;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:Symbol;}
@list l0:level2
{mso-level-number-format:bullet;
mso-level-text:o;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:"Courier New";}
@list l0:level3
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:Wingdings;}
@list l0:level4
{mso-level-number-format:bullet;
mso-level-text:\F0B7;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:Symbol;}
@list l0:level5
{mso-level-number-format:bullet;
mso-level-text:o;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:"Courier New";}
@list l0:level6
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:Wingdings;}
@list l0:level7
{mso-level-number-format:bullet;
mso-level-text:\F0B7;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:Symbol;}
@list l0:level8
{mso-level-number-format:bullet;
mso-level-text:o;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:"Courier New";}
@list l0:level9
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:Wingdings;}
ol
{margin-bottom:0mm;}
ul
{margin-bottom:0mm;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]--></head><body lang=EN-GB link="#0563C1" vlink="#954F72"><div class=WordSection1><p class=MsoNormal><a href="https://www.amazon.co.uk/Effective-Python-Specific-Software-Development/dp/0134853989">https://www.amazon.co.uk/Effective-Python-Specific-Software-Development/dp/0134853989</a><span style='color:#44546A'><o:p></o:p></span></p><p class=MsoNormal><span style='color:#44546A'>I have read the first edition of this book and it is really excellent.<o:p></o:p></span></p><p class=MsoNormal><span style='color:#44546A'>It solidifies and extends an intermediate/beginner’s knowledge of when NOT to use modern clever python idioms.<o:p></o:p></span></p><p class=MsoNormal><span style='color:#44546A'>Succinct and nearly all useful; and not preachy like some software books.<o:p></o:p></span></p><p class=MsoNormal><span style='color:#44546A'><o:p> </o:p></span></p><p class=MsoNormal><span style='color:#44546A'>Python is a much bigger language than it was in 2006 when troggle was written. (If you don’t believe me, try to read this article: </span><a href="https://effectivepython.com/2019/12/18/prefer-class-decorators-over-metaclasses">https://effectivepython.com/2019/12/18/prefer-class-decorators-over-metaclasses</a> )<span style='color:#44546A'><o:p></o:p></span></p><p class=MsoNormal><span style='color:#44546A'><o:p> </o:p></span></p><p class=MsoNormal><span style='color:#44546A'>Django uses quite a few clever tricks that a student who learned python to do data analysis as part of an engineering or bioinformatics degree would not have come across. Specifically I doubt that students are taught what ‘patterns’ are in departments other than computer science; or the techniques for code ‘refactoring’ and how they are so useful.<o:p></o:p></span></p><p class=MsoNormal><span style='color:#44546A'><o:p> </o:p></span></p><p class=MsoNormal><span style='color:#44546A'>But we should be careful to comment in the troggle code whenever there is anything subtle that a 1990s pascal programmer might not be aware of.<o:p></o:p></span></p><p class=MsoNormal><span style='color:#44546A'><o:p> </o:p></span></p><p class=MsoNormal><span style='color:#44546A'>e.g. </span><span style='font-family:"Helvetica","sans-serif";color:#333333;background:white'>An assignment expression—also known as the <em><span style='font-family:"Helvetica","sans-serif"'>walrus operator</span></em>—is a new syntax introduced in Python 3.8 <br></span><a href="https://effectivepython.com/2020/02/02/prevent-repetition-with-assignment-expressions">https://effectivepython.com/2020/02/02/prevent-repetition-with-assignment-expressions</a><o:p></o:p></p><p class=MsoNormal>which we won’t be using (yet).<span style='color:#44546A'><o:p></o:p></span></p><p class=MsoNormal><span style='color:#44546A'><o:p> </o:p></span></p><p class=MsoNormal><span style='color:#44546A'>updates & code online at </span><a href="https://github.com/bslatkin/effectivepython">https://github.com/bslatkin/effectivepython</a><span style='color:#44546A'><o:p></o:p></span></p><p class=MsoNormal><span style='color:#44546A'><o:p> </o:p></span></p><p class=MsoNormal><span style='color:#44546A'><o:p> </o:p></span></p><p class=MsoNormal><span style='color:#44546A'>Refactoring: this is what will allow us to move away from Django while keeping troggle running without a break:<o:p></o:p></span></p><p class=MsoListParagraph style='text-indent:-18.0pt;mso-list:l0 level1 lfo1'><![if !supportLists]><span style='font-family:Symbol;color:#44546A'><span style='mso-list:Ignore'>·<span style='font:7.0pt "Times New Roman"'> </span></span></span><![endif]><a href="https://speakerdeck.com/pycon2016/brett-slatkin-refactoring-python-why-and-how-to-restructure-your-code">https://speakerdeck.com/pycon2016/brett-slatkin-refactoring-python-why-and-how-to-restructure-your-code</a><span style='color:#44546A'><o:p></o:p></span></p><p class=MsoListParagraph style='text-indent:-18.0pt;mso-list:l0 level1 lfo1'><![if !supportLists]><span style='font-family:Symbol'><span style='mso-list:Ignore'>·<span style='font:7.0pt "Times New Roman"'> </span></span></span><![endif]><a href="https://martinfowler.com/tags/refactoring.html">https://martinfowler.com/tags/refactoring.html</a><o:p></o:p></p><p class=MsoListParagraph style='text-indent:-18.0pt;mso-list:l0 level1 lfo1'><![if !supportLists]><span style='font-family:Symbol;color:#44546A'><span style='mso-list:Ignore'>·<span style='font:7.0pt "Times New Roman"'> </span></span></span><![endif]><a href="https://www.amazon.co.uk/Refactoring-Improving-Existing-Addison-Wesley-Technology/dp/0134757599/ref=msx_wsirn_v1_5/262-9963705-7092713?_encoding=UTF8&pd_rd_i=0134757599&pd_rd_r=a3dcd1d0-33c2-4d92-865b-0c6c02797196&pd_rd_w=gaeIZ&pd_rd_wg=kqkSE&pf_rd_p=2c73497e-0658-4f6d-8f3c-06c50c0881ec&pf_rd_r=R5CYDBNTT0A2F22S6R57&psc=1&refRID=R5CYDBNTT0A2F22S6R57">https://www.amazon.co.uk/Refactoring-Improving-Existing-Addison-Wesley-Technology/dp/0134757599/ref=msx_wsirn_v1_5/262-9963705-7092713?_encoding=UTF8&pd_rd_i=0134757599&pd_rd_r=a3dcd1d0-33c2-4d92-865b-0c6c02797196&pd_rd_w=gaeIZ&pd_rd_wg=kqkSE&pf_rd_p=2c73497e-0658-4f6d-8f3c-06c50c0881ec&pf_rd_r=R5CYDBNTT0A2F22S6R57&psc=1&refRID=R5CYDBNTT0A2F22S6R57</a><span style='color:#44546A'><o:p></o:p></span></p><p class=MsoListParagraph style='text-indent:-18.0pt;mso-list:l0 level1 lfo1'><![if !supportLists]><span style='font-family:Symbol;color:#44546A'><span style='mso-list:Ignore'>·<span style='font:7.0pt "Times New Roman"'> </span></span></span><![endif]><a href="https://refactoring.com/catalog/">https://refactoring.com/catalog/</a><span style='color:#44546A'><o:p></o:p></span></p><p class=MsoNormal><span style='color:#44546A'><o:p> </o:p></span></p><p class=MsoNormal><span style='color:#44546A'><o:p> </o:p></span></p><div><div style='border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0mm 0mm 0mm'><p class=MsoNormal><b><span lang=EN-US style='font-size:10.0pt;font-family:"Tahoma","sans-serif";mso-fareast-language:EN-GB'>From:</span></b><span lang=EN-US style='font-size:10.0pt;font-family:"Tahoma","sans-serif";mso-fareast-language:EN-GB'> Philip Sargent [Gmail] [mailto:philip.sargent@gmail.com] <br><b>Sent:</b> 23 July 2020 22:47<br><b>To:</b> 'Philip Sargent - Klebos'<br><b>Subject:</b> 90 essential python tips<o:p></o:p></span></p></div></div><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><b><span style='color:#5B9BD5'>1. Pythonic Thinking<o:p></o:p></span></b></p><p class=MsoNormal> Item 1: Know Which Version of Python You’re Using<o:p></o:p></p><p class=MsoNormal> Item 2: Follow the PEP 8 Style Guide<o:p></o:p></p><p class=MsoNormal> Item 3: Know the Differences Between bytes and str<o:p></o:p></p><p class=MsoNormal> Item 4: Prefer Interpolated F-Strings Over C-style Format Strings and str.format<o:p></o:p></p><p class=MsoNormal> Item 5: Write Helper Functions Instead of Complex Expressions<o:p></o:p></p><p class=MsoNormal> Item 6: Prefer Multiple Assignment Unpacking Over Indexing<o:p></o:p></p><p class=MsoNormal> Item 7: Prefer enumerate Over range<o:p></o:p></p><p class=MsoNormal> Item 8: Use zip to Process Iterators in Parallel<o:p></o:p></p><p class=MsoNormal> Item 9: Avoid else Blocks After for and while Loops<o:p></o:p></p><p class=MsoNormal> Item 10: Prevent Repetition with Assignment Expressions<o:p></o:p></p><p class=MsoNormal><b><span style='color:#5B9BD5'>2. Lists and Dictionaries<o:p></o:p></span></b></p><p class=MsoNormal> Item 11: Know How to Slice Sequences<o:p></o:p></p><p class=MsoNormal> Item 12: Avoid Striding and Slicing in a Single Expression<o:p></o:p></p><p class=MsoNormal> Item 13: Prefer Catch-All Unpacking Over Slicing<o:p></o:p></p><p class=MsoNormal> Item 14: Sort by Complex Criteria Using the key Parameter<o:p></o:p></p><p class=MsoNormal> Item 15: Be Cautious When Relying on dict Insertion Ordering<o:p></o:p></p><p class=MsoNormal> Item 16: Prefer get Over in and KeyError to Handle Missing Dictionary Keys<o:p></o:p></p><p class=MsoNormal> Item 17: Prefer defaultdict Over setdefault to Handle Missing Items in Internal State<o:p></o:p></p><p class=MsoNormal> Item 18: Know How to Construct Key-Dependent Default Values with __missing__<o:p></o:p></p><p class=MsoNormal><b><span style='color:#5B9BD5'>3. Functions<o:p></o:p></span></b></p><p class=MsoNormal> Item 19: Never Unpack More Than Three Variables When Functions Return Multiple Values<o:p></o:p></p><p class=MsoNormal> Item 20: Prefer Raising Exceptions to Returning None<o:p></o:p></p><p class=MsoNormal> Item 21: Know How Closures Interact with Variable Scope<o:p></o:p></p><p class=MsoNormal> Item 22: Reduce Visual Noise with Variable Positional Arguments<o:p></o:p></p><p class=MsoNormal> Item 23: Provide Optional Behavior with Keyword Arguments<o:p></o:p></p><p class=MsoNormal> Item 24: Use None and Docstrings to Specify Dynamic Default Arguments<o:p></o:p></p><p class=MsoNormal> Item 25: Enforce Clarity with Keyword-Only and Positional-Only Arguments<o:p></o:p></p><p class=MsoNormal> Item 26: Define Function Decorators with functools.wraps<o:p></o:p></p><p class=MsoNormal><b><span style='color:#5B9BD5'>4. Comprehensions and Generators<o:p></o:p></span></b></p><p class=MsoNormal> Item 27: Use Comprehensions Instead of map and filter<o:p></o:p></p><p class=MsoNormal> Item 28: Avoid More Than Two Control Subexpressions in Comprehensions<o:p></o:p></p><p class=MsoNormal> Item 29: Avoid Repeated Work in Comprehensions by Using Assignment Expressions<o:p></o:p></p><p class=MsoNormal> Item 30: Consider Generators Instead of Returning Lists<o:p></o:p></p><p class=MsoNormal> Item 31: Be Defensive When Iterating Over Arguments<o:p></o:p></p><p class=MsoNormal> Item 32: Consider Generator Expressions for Large List Comprehensions<o:p></o:p></p><p class=MsoNormal> Item 33: Compose Multiple Generators with yield from<o:p></o:p></p><p class=MsoNormal> Item 34: Avoid Injecting Data into Generators with send<o:p></o:p></p><p class=MsoNormal> Item 35: Avoid Causing State Transitions in Generators with throw<o:p></o:p></p><p class=MsoNormal> Item 36: Consider itertools for Working with Iterators and Generators<o:p></o:p></p><p class=MsoNormal><b><span style='color:#5B9BD5'>5. Classes and Interfaces<o:p></o:p></span></b></p><p class=MsoNormal> Item 37: Compose Classes Instead of Nesting Many Levels of Built-in Types<o:p></o:p></p><p class=MsoNormal> Item 38: Accept Functions Instead of Classes for Simple Interfaces<o:p></o:p></p><p class=MsoNormal> Item 39: Use @classmethod Polymorphism to Construct Objects Generically<o:p></o:p></p><p class=MsoNormal> Item 40: Initialize Parent Classes with super<o:p></o:p></p><p class=MsoNormal> Item 41: Consider Composing Functionality with Mix-in Classes<o:p></o:p></p><p class=MsoNormal> Item 42: Prefer Public Attributes Over Private Ones<o:p></o:p></p><p class=MsoNormal> Item 43: Inherit from collections.abc for Custom Container Types<o:p></o:p></p><p class=MsoNormal><b><span style='color:#5B9BD5'>6. Metaclasses and Attributes<o:p></o:p></span></b></p><p class=MsoNormal> Item 44: Use Plain Attributes Instead of Setter and Getter Methods<o:p></o:p></p><p class=MsoNormal> Item 45: Consider @property Instead of Refactoring Attributes<o:p></o:p></p><p class=MsoNormal> Item 46: Use Descriptors for Reusable @property Methods<o:p></o:p></p><p class=MsoNormal> Item 47: Use __getattr__, __getattribute__, and __setattr__ for Lazy Attributes<o:p></o:p></p><p class=MsoNormal> Item 48: Validate Subclasses with __init_subclass__<o:p></o:p></p><p class=MsoNormal> Item 49: Register Class Existence with __init_subclass__<o:p></o:p></p><p class=MsoNormal> Item 50: Annotate Class Attributes with __set_name__<o:p></o:p></p><p class=MsoNormal> Item 51: Prefer Class Decorators Over Metaclasses for Composable Class Extensions<o:p></o:p></p><p class=MsoNormal><b><span style='color:#5B9BD5'>7. Concurrency and Parallelism<o:p></o:p></span></b></p><p class=MsoNormal> Item 52: Use subprocess to Manage Child Processes<o:p></o:p></p><p class=MsoNormal> Item 53: Use Threads for Blocking I/O, Avoid for Parallelism<o:p></o:p></p><p class=MsoNormal> Item 54: Use Lock to Prevent Data Races in Threads<o:p></o:p></p><p class=MsoNormal> Item 55: Use Queue to Coordinate Work Between Threads<o:p></o:p></p><p class=MsoNormal> Item 56: Know How to Recognize When Concurrency Is Necessary<o:p></o:p></p><p class=MsoNormal> Item 57: Avoid Creating New Thread Instances for On-demand Fan-out<o:p></o:p></p><p class=MsoNormal> Item 58: Understand How Using Queue for Concurrency Requires Refactoring<o:p></o:p></p><p class=MsoNormal> Item 59: Consider ThreadPoolExecutor When Threads Are Necessary for Concurrency<o:p></o:p></p><p class=MsoNormal> Item 60: Achieve Highly Concurrent I/O with Coroutines<o:p></o:p></p><p class=MsoNormal> Item 61: Know How to Port Threaded I/O to asyncio<o:p></o:p></p><p class=MsoNormal> Item 62: Mix Threads and Coroutines to Ease the Transition to asyncio<o:p></o:p></p><p class=MsoNormal> Item 63: Avoid Blocking the asyncio Event Loop to Maximize Responsiveness<o:p></o:p></p><p class=MsoNormal> Item 64: Consider concurrent.futures for True Parallelism<o:p></o:p></p><p class=MsoNormal><b><span style='color:#5B9BD5'>8. Robustness and Performance<o:p></o:p></span></b></p><p class=MsoNormal> Item 65: Take Advantage of Each Block in try/except/else/finally<o:p></o:p></p><p class=MsoNormal> Item 66: Consider contextlib and with Statements for Reusable try/finally Behavior<o:p></o:p></p><p class=MsoNormal> Item 67: Use datetime Instead of time for Local Clocks<o:p></o:p></p><p class=MsoNormal> Item 68: Make pickle Reliable with copyreg<o:p></o:p></p><p class=MsoNormal> Item 69: Use decimal When Precision Is Paramount<o:p></o:p></p><p class=MsoNormal> Item 70: Profile Before Optimizing<o:p></o:p></p><p class=MsoNormal> Item 71: Prefer deque for Producer–Consumer Queues for Producer–Consumer Queues<o:p></o:p></p><p class=MsoNormal> Item 72: Consider Searching Sorted Sequences with bisect<o:p></o:p></p><p class=MsoNormal> Item 73: Know How to Use heapq for Priority Queues<o:p></o:p></p><p class=MsoNormal> Item 74: Consider memoryview and bytearray for Zero-Copy Interactions with bytes<o:p></o:p></p><p class=MsoNormal><b><span style='color:#5B9BD5'>9. Testing and Debugging<o:p></o:p></span></b></p><p class=MsoNormal> Item 75: Use repr Strings for Debugging Output<o:p></o:p></p><p class=MsoNormal> Item 76: Verify Related Behaviors in TestCase Subclasses<o:p></o:p></p><p class=MsoNormal> Item 77: Isolate Tests from Each Other with setUp, tearDown, setUpModule, and tearDownModule<o:p></o:p></p><p class=MsoNormal> Item 78: Use Mocks to Test Code with Complex Dependencies<o:p></o:p></p><p class=MsoNormal> Item 79: Encapsulate Dependencies to Facilitate Mocking and Testing<o:p></o:p></p><p class=MsoNormal> Item 80: Consider Interactive Debugging with pdb<o:p></o:p></p><p class=MsoNormal> Item 81: Use tracemalloc to Understand Memory Usage and Leaks<o:p></o:p></p><p class=MsoNormal><b><span style='color:#5B9BD5'>10. Collaboration<o:p></o:p></span></b></p><p class=MsoNormal> Item 82: Know Where to Find Community-Built Modules<o:p></o:p></p><p class=MsoNormal> Item 83: Use Virtual Environments for Isolated and Reproducible Dependencies<o:p></o:p></p><p class=MsoNormal> Item 84: Write Docstrings for Every Function, Class, and Module<o:p></o:p></p><p class=MsoNormal> Item 85: Use Packages to Organize Modules and Provide Stable APIs<o:p></o:p></p><p class=MsoNormal> Item 86: Consider Module-Scoped Code to Configure Deployment Environments<o:p></o:p></p><p class=MsoNormal> Item 87: Define a Root Exception to Insulate Callers from APIs<o:p></o:p></p><p class=MsoNormal> Item 88: Know How to Break Circular Dependencies<o:p></o:p></p><p class=MsoNormal> Item 89: Consider warnings to Refactor and Migrate Usage<o:p></o:p></p><p class=MsoNormal> Item 90: Consider Static Analysis via typing to Obviate Bugs<o:p></o:p></p></div></body></html>