├── CNAME ├── Makefile ├── README.md ├── __slots__magic.rst ├── _static ├── cover.pdf ├── cover.png ├── custom.css └── epub.css ├── _templates └── breadcrumbs.html ├── args_and_kwargs.rst ├── classes.rst ├── collections.rst ├── comprehensions.rst ├── conf.py ├── context_managers.rst ├── coroutines.rst ├── debugging.rst ├── decorators.rst ├── enumerate.rst ├── exceptions.rst ├── flaskstyle.sty ├── for_-_else.rst ├── function_caching.rst ├── generators.rst ├── global_&_return.rst ├── index.rst ├── lambdas.rst ├── make.bat ├── map_filter.rst ├── mutation.rst ├── object_introspection.rst ├── one_liners.rst ├── open_function.rst ├── params.json ├── python_c_extension.rst ├── python_modules_in_c.rst ├── set_-_data_structure.rst ├── targeting_python_2_3.rst ├── ternary_operators.rst ├── virtual_environment.rst └── zip.rst /CNAME: -------------------------------------------------------------------------------- 1 | book.pythontips.com 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PythonTips.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PythonTips.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/PythonTips" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PythonTips" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Intermediate Python Book Cover](_static/cover.png) 2 | 3 | Intermediate Python 4 | =================== 5 | 6 | Python is an amazing language with a strong and friendly community of programmers. However, there is a lack of documentation on what to learn after getting the basics of Python down your throat. Through this book I aim to solve this problem. I will give you bits of information about some interesting topics which you can further explore. 7 | 8 | The topics which are discussed in this book will open your mind to some nice corners of Python language. This book is an outcome of my desire to have something like this when I was beginning to learn Python. 9 | 10 | If you are a beginner, intermediate or even an advanced programmer there is something for you in this book. 11 | 12 | Please note that this book is not a tutorial and does not teach you Python. The topics are not explained in-depth and only the minimum required information is given. 13 | 14 | I am sure you are as excited as I am. So, let’s start! 15 | 16 | Note: This book is a work in progress. If you find anything which you can further improve (I know you will find a lot of stuff) then kindly submit a pull request. :) 17 | 18 | Moreover, if you want to add more content to this book then kindly submit a pull request and I will be more than happy to merge it. :+1: 19 | 20 | ------------------- 21 | 22 | **Note:** If you want to tip me for my work then you can buy the donation version of this book from [Gumroad](https://gum.co/intermediate_python). Apart from that, if this book somehow helps you then kindly share your experience with [me](mailto:yasoob.khld@gmail.com). I would really appreciate it. 23 | 24 | ------------------- 25 | 26 | Table of Contents: 27 | ------------------ 28 | 1) Programmer tools 29 | - [Virtual Environment](virtual_environment.rst) 30 | - [Debugging](debugging.rst) 31 | - [Object introspection](object_introspection.rst) 32 | 2) Syntax 33 | - [Exceptions](exceptions.rst) 34 | - [For - Else](for_-_else.rst) 35 | - [Ternary Operators](ternary_operators.rst) 36 | - [Global & Return](global_&_return.rst) 37 | - [Open function](open_function.rst) 38 | - [\*args and \*\*kwargs](args_and_kwargs.rst) 39 | - [Context managers](context_managers.rst) 40 | 3) Functional programming 41 | - [Enumerate](enumerate.rst) 42 | - [Lambdas](lambdas.rst) 43 | - [``set`` Data Structure](set_-_data_structure.rst) 44 | - [Map & Filter](map_filter.rst) 45 | - [Comprehensions](comprehensions.rst) 46 | 4) Data structures 47 | - [Generators](generators.rst) 48 | - [Coroutines](coroutines.rst) 49 | - [Classes](classes.rst) 50 | 5) Data types 51 | - [Collections](collections.rst) 52 | - [Mutation](mutation.rst) 53 | - [\_\_slots\_\_ Magic](__slots__magic.rst) 54 | 6) Decorators 55 | - [What is a decorator?](decorators.rst) 56 | - [Function caching](function_caching.rst) 57 | 7) Extras 58 | - [One Liners](one_liners.rst) 59 | - [Targeting Python 2+3](targeting_python_2_3.rst) 60 | - [Python C extensions](python_c_extension.rst) 61 | 62 | Author: 63 | ------ 64 | 65 | - [Muhammad Yasoob Ullah Khalid](https://github.com/yasoob) 66 | 67 | Acknowledgement: 68 | ---------------- 69 | 70 | - [Philipp Hagemeister](https://github.com/phihag): 71 | 72 | He wrote the chapter on Open function. Thanks Philipp! :+1: 73 | 74 | Translation: 75 | ------------ 76 | If you want to translate this book in any other language then kindly let [me know](mailto:yasoob.khld@gmail.com). I would love your contribution. The currently translated versions are listed below: 77 | 78 | - [Chinese](https://github.com/eastlakeside/interpy-zh) 79 | - [Russian](https://github.com/lancelote/interpy-ru) 80 | - [Korean](https://github.com/DDanggle/interpy-kr) 81 | - [Portuguese](https://github.com/joanasouza/intermediatePython) 82 | - [Spanish](https://github.com/cursospython/LibroPython) 83 | 84 | License: 85 | ------- 86 | 87 | This book is released under the [following](http://creativecommons.org/licenses/by-nc-sa/4.0/) CC license (CC BY-NC-SA 4.0). 88 | 89 | If you end up using/recommending this book to someone then kindly [let me know](mailto:yasoob.khld@gmail.com). :smile: 90 | 91 | 92 | -------------------------------------------------------------------------------- /__slots__magic.rst: -------------------------------------------------------------------------------- 1 | \_\_slots\_\_ Magic 2 | ------------------- 3 | 4 | In Python every class can have instance attributes. By default Python 5 | uses a dict to store an object’s instance attributes. This is really 6 | helpful as it allows setting arbitrary new attributes at runtime. 7 | 8 | However, for small classes with known attributes it might be a 9 | bottleneck. The ``dict`` wastes a lot of RAM. Python can’t just allocate 10 | a static amount of memory at object creation to store all the 11 | attributes. Therefore it sucks a lot of RAM if you create a lot of 12 | objects (I am talking in thousands and millions). Still there is a way 13 | to circumvent this issue. It involves the usage of ``__slots__`` to 14 | tell Python not to use a dict, and only allocate space for a fixed set 15 | of attributes. Here is an example with and without ``__slots__``: 16 | 17 | **Without** ``__slots__``: 18 | 19 | .. code:: python 20 | 21 | class MyClass(object): 22 | def __init__(self, name, identifier): 23 | self.name = name 24 | self.identifier = identifier 25 | self.set_up() 26 | # ... 27 | 28 | **With** ``__slots__``: 29 | 30 | .. code:: python 31 | 32 | class MyClass(object): 33 | __slots__ = ['name', 'identifier'] 34 | def __init__(self, name, identifier): 35 | self.name = name 36 | self.identifier = identifier 37 | self.set_up() 38 | # ... 39 | 40 | The second piece of code will reduce the burden on your RAM. Some people 41 | have seen almost 40 to 50% reduction in RAM usage by using this 42 | technique. 43 | 44 | On a sidenote, you might want to give PyPy a try. It does all of these 45 | optimizations by default. 46 | 47 | 48 | Below you can see an example showing exact memory usage with and without ``__slots__`` done in IPython thanks to https://github.com/ianozsvald/ipython_memory_usage 49 | 50 | .. code:: python 51 | 52 | Python 3.4.3 (default, Jun 6 2015, 13:32:34) 53 | Type "copyright", "credits" or "license" for more information. 54 | 55 | IPython 4.0.0 -- An enhanced Interactive Python. 56 | ? -> Introduction and overview of IPython's features. 57 | %quickref -> Quick reference. 58 | help -> Python's own help system. 59 | object? -> Details about 'object', use 'object??' for extra details. 60 | 61 | In [1]: import ipython_memory_usage.ipython_memory_usage as imu 62 | 63 | In [2]: imu.start_watching_memory() 64 | In [2] used 0.0000 MiB RAM in 5.31s, peaked 0.00 MiB above current, total RAM usage 15.57 MiB 65 | 66 | In [3]: %cat slots.py 67 | class MyClass(object): 68 | __slots__ = ['name', 'identifier'] 69 | def __init__(self, name, identifier): 70 | self.name = name 71 | self.identifier = identifier 72 | 73 | num = 1024*256 74 | x = [MyClass(1,1) for i in range(num)] 75 | In [3] used 0.2305 MiB RAM in 0.12s, peaked 0.00 MiB above current, total RAM usage 15.80 MiB 76 | 77 | In [4]: from slots import * 78 | In [4] used 9.3008 MiB RAM in 0.72s, peaked 0.00 MiB above current, total RAM usage 25.10 MiB 79 | 80 | In [5]: %cat noslots.py 81 | class MyClass(object): 82 | def __init__(self, name, identifier): 83 | self.name = name 84 | self.identifier = identifier 85 | 86 | num = 1024*256 87 | x = [MyClass(1,1) for i in range(num)] 88 | In [5] used 0.1758 MiB RAM in 0.12s, peaked 0.00 MiB above current, total RAM usage 25.28 MiB 89 | 90 | In [6]: from noslots import * 91 | In [6] used 22.6680 MiB RAM in 0.80s, peaked 0.00 MiB above current, total RAM usage 47.95 MiB 92 | -------------------------------------------------------------------------------- /_static/cover.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasoob/intermediatePython/257709f4acb61539bf654fc6a5b72ac5e2c86ba0/_static/cover.pdf -------------------------------------------------------------------------------- /_static/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasoob/intermediatePython/257709f4acb61539bf654fc6a5b72ac5e2c86ba0/_static/cover.png -------------------------------------------------------------------------------- /_static/custom.css: -------------------------------------------------------------------------------- 1 | 2 | @media screen and (min-width: 1000px){ 3 | iframe{ 4 | margin-left: 330px; 5 | } 6 | } -------------------------------------------------------------------------------- /_static/epub.css: -------------------------------------------------------------------------------- 1 | /* 2 | * epub.css_t 3 | * ~~~~~~~~~~ 4 | * 5 | * Sphinx stylesheet -- epub theme. 6 | * 7 | * :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | /* -- main layout ----------------------------------------------------------- */ 13 | h1{ 14 | border-bottom: 2px solid black; 15 | padding-bottom: 10px; 16 | margin-bottom: 30px; 17 | } 18 | 19 | strong{ 20 | /*font-size: 20px;*/ 21 | } 22 | 23 | div.clearer { 24 | clear: both; 25 | } 26 | 27 | a:link, a:visited { 28 | color: #3333ff; 29 | text-decoration: none; 30 | } 31 | 32 | img { 33 | border: 0; 34 | max-width: 100%; 35 | } 36 | 37 | ul.simple { 38 | list-style: none; 39 | margin-left: 0; 40 | padding-left: 0; 41 | } 42 | 43 | ul.simple li { 44 | padding-left: 1em; 45 | text-indent: -1em; 46 | } 47 | 48 | ul.simple li:before { 49 | content: "»"; 50 | padding-right: 5px; 51 | } 52 | 53 | li.toctree-l1,li.toctree-l2{ 54 | display: block; 55 | } 56 | /* -- relbar ---------------------------------------------------------------- */ 57 | 58 | div.related { 59 | width: 100%; 60 | font-family: sans-serif; 61 | font-size: 90%; 62 | display: none; 63 | } 64 | 65 | div.footer{ 66 | display: none; 67 | } 68 | 69 | div.related h3 { 70 | display: none; 71 | } 72 | 73 | div.related ul { 74 | margin: 0; 75 | padding: 0 0 0 10px; 76 | list-style: none; 77 | } 78 | 79 | div.related li { 80 | display: inline; 81 | } 82 | 83 | div.related li.right { 84 | float: right; 85 | margin-right: 5px; 86 | } 87 | 88 | div pre{ 89 | padding: 20px; 90 | } 91 | 92 | div.highlight{ 93 | background-color: rgb(245, 243, 243); 94 | } 95 | /* -- sidebar --------------------------------------------------------------- */ 96 | 97 | div.sphinxsidebarwrapper { 98 | padding: 10px 5px 0 10px; 99 | } 100 | 101 | div.sphinxsidebar { 102 | float: left; 103 | width: 230px; 104 | margin-left: -100%; 105 | font-size: 90%; 106 | } 107 | 108 | div.sphinxsidebar ul { 109 | list-style: none; 110 | } 111 | 112 | div.sphinxsidebar ul ul, 113 | div.sphinxsidebar ul.want-points { 114 | margin-left: 20px; 115 | list-style: square; 116 | } 117 | 118 | div.sphinxsidebar ul ul { 119 | margin-top: 0; 120 | margin-bottom: 0; 121 | } 122 | 123 | div.sphinxsidebar form { 124 | margin-top: 10px; 125 | } 126 | 127 | div.sphinxsidebar input { 128 | border: 1px solid #98dbcc; 129 | font-family: sans-serif; 130 | font-size: 100%; 131 | } 132 | 133 | img { 134 | border: 0; 135 | max-width: 100%; 136 | } 137 | 138 | /* -- search page ----------------------------------------------------------- */ 139 | 140 | ul.search { 141 | margin: 10px 0 0 20px; 142 | padding: 0; 143 | } 144 | 145 | ul.search li { 146 | padding: 5px 0 5px 20px; 147 | background-image: url(file.png); 148 | background-repeat: no-repeat; 149 | background-position: 0 7px; 150 | } 151 | 152 | ul.search li a { 153 | font-weight: bold; 154 | } 155 | 156 | ul.search li div.context { 157 | color: #888; 158 | margin: 2px 0 0 30px; 159 | text-align: left; 160 | } 161 | 162 | ul.keywordmatches li.goodmatch a { 163 | font-weight: bold; 164 | } 165 | 166 | /* -- index page ------------------------------------------------------------ */ 167 | 168 | table.contentstable { 169 | width: 90%; 170 | } 171 | 172 | table.contentstable p.biglink { 173 | line-height: 150%; 174 | } 175 | 176 | a.biglink { 177 | font-size: 130%; 178 | } 179 | 180 | span.linkdescr { 181 | font-style: italic; 182 | padding-top: 5px; 183 | font-size: 90%; 184 | } 185 | 186 | /* -- general index --------------------------------------------------------- */ 187 | 188 | table.indextable td { 189 | text-align: left; 190 | vertical-align: top; 191 | } 192 | 193 | table.indextable dl, table.indextable dd { 194 | margin-top: 0; 195 | margin-bottom: 0; 196 | } 197 | 198 | table.indextable tr.pcap { 199 | height: 10px; 200 | } 201 | 202 | table.indextable tr.cap { 203 | margin-top: 10px; 204 | background-color: #f2f2f2; 205 | } 206 | 207 | img.toggler { 208 | margin-right: 3px; 209 | margin-top: 3px; 210 | cursor: pointer; 211 | } 212 | 213 | /* -- general body styles --------------------------------------------------- */ 214 | 215 | a.headerlink { 216 | visibility: hidden; 217 | } 218 | 219 | div.body p.caption { 220 | text-align: inherit; 221 | } 222 | 223 | div.body td { 224 | text-align: left; 225 | } 226 | 227 | .field-list ul { 228 | padding-left: 100%; 229 | } 230 | 231 | .first { 232 | margin-top: 0 !important; 233 | } 234 | 235 | p.rubric { 236 | margin-top: 30px; 237 | font-weight: bold; 238 | } 239 | 240 | .align-left { 241 | text-align: left; 242 | } 243 | 244 | .align-center { 245 | text-align: center; 246 | } 247 | 248 | .align-right { 249 | text-align: right; 250 | } 251 | 252 | /* -- sidebars -------------------------------------------------------------- */ 253 | 254 | div.sidebar { 255 | margin: 0 0 0.5em 1em; 256 | border: 1px solid #ddb; 257 | padding: 7px 7px 0 7px; 258 | background-color: #ffe; 259 | width: 40%; 260 | float: right; 261 | } 262 | 263 | p.sidebar-title { 264 | font-weight: bold; 265 | } 266 | 267 | /* -- topics ---------------------------------------------------------------- */ 268 | 269 | div.topic { 270 | border: 1px solid #ccc; 271 | padding: 7px 7px 0 7px; 272 | margin: 10px 0 10px 0; 273 | } 274 | 275 | p.topic-title { 276 | font-size: 110%; 277 | font-weight: bold; 278 | margin-top: 10px; 279 | } 280 | 281 | /* -- admonitions ----------------------------------------------------------- */ 282 | 283 | div.admonition { 284 | margin-top: 10px; 285 | margin-bottom: 10px; 286 | padding: 7px; 287 | } 288 | 289 | div.admonition dt { 290 | font-weight: bold; 291 | } 292 | 293 | div.admonition dl { 294 | margin-bottom: 0; 295 | } 296 | 297 | p.admonition-title { 298 | margin: 0px 10px 5px 0px; 299 | font-weight: bold; 300 | } 301 | 302 | div.body p.centered { 303 | text-align: center; 304 | margin-top: 25px; 305 | } 306 | 307 | /* -- tables ---------------------------------------------------------------- */ 308 | 309 | table.docutils { 310 | border: 0; 311 | border-collapse: collapse; 312 | } 313 | 314 | table caption span.caption-number { 315 | font-style: italic; 316 | } 317 | 318 | table caption span.caption-text { 319 | } 320 | 321 | table.docutils td, table.docutils th { 322 | padding: 1px 8px 1px 5px; 323 | border-top: 0; 324 | border-left: 0; 325 | border-right: 0; 326 | border-bottom: 1px solid #aaa; 327 | } 328 | 329 | table.field-list td, table.field-list th { 330 | border: 0 !important; 331 | } 332 | 333 | table.footnote td, table.footnote th { 334 | border: 0 !important; 335 | } 336 | 337 | th { 338 | text-align: left; 339 | padding-right: 5px; 340 | } 341 | 342 | table.citation { 343 | border-left: solid 1px gray; 344 | margin-left: 1px; 345 | } 346 | 347 | table.citation td { 348 | border-bottom: none; 349 | } 350 | 351 | /* -- figures --------------------------------------------------------------- */ 352 | 353 | div.figure p.caption span.caption-number { 354 | font-style: italic; 355 | } 356 | 357 | div.figure p.caption span.caption-text { 358 | } 359 | 360 | /* -- other body styles ----------------------------------------------------- */ 361 | 362 | ol.arabic { 363 | list-style: decimal; 364 | } 365 | 366 | ol.loweralpha { 367 | list-style: lower-alpha; 368 | } 369 | 370 | ol.upperalpha { 371 | list-style: upper-alpha; 372 | } 373 | 374 | ol.lowerroman { 375 | list-style: lower-roman; 376 | } 377 | 378 | ol.upperroman { 379 | list-style: upper-roman; 380 | } 381 | 382 | dl { 383 | margin-bottom: 15px; 384 | } 385 | 386 | dd p { 387 | margin-top: 0px; 388 | } 389 | 390 | dd ul, dd table { 391 | margin-bottom: 10px; 392 | } 393 | 394 | dd { 395 | margin-top: 3px; 396 | margin-bottom: 10px; 397 | margin-left: 30px; 398 | } 399 | 400 | dt:target, .highlighted { 401 | background-color: #ddd; 402 | } 403 | 404 | dl.glossary dt { 405 | font-weight: bold; 406 | font-size: 110%; 407 | } 408 | 409 | .field-list ul { 410 | margin: 0; 411 | padding-left: 1em; 412 | } 413 | 414 | .field-list p { 415 | margin: 0; 416 | } 417 | 418 | .optional { 419 | font-size: 130%; 420 | } 421 | 422 | .sig-paren { 423 | font-size: larger; 424 | } 425 | 426 | .versionmodified { 427 | font-style: italic; 428 | } 429 | 430 | .system-message { 431 | background-color: #fda; 432 | padding: 5px; 433 | border: 3px solid red; 434 | } 435 | 436 | .footnote:target { 437 | background-color: #dddddd; 438 | } 439 | 440 | .line-block { 441 | display: block; 442 | margin-top: 1em; 443 | margin-bottom: 1em; 444 | } 445 | 446 | .line-block .line-block { 447 | margin-top: 0; 448 | margin-bottom: 0; 449 | margin-left: 1.5em; 450 | } 451 | 452 | .guilabel, .menuselection { 453 | font-style: italic; 454 | } 455 | 456 | .accelerator { 457 | text-decoration: underline; 458 | } 459 | 460 | .classifier { 461 | font-style: oblique; 462 | } 463 | 464 | abbr, acronym { 465 | border-bottom: dotted 1px; 466 | cursor: help; 467 | } 468 | 469 | /* -- code displays --------------------------------------------------------- */ 470 | 471 | pre { 472 | font-family: monospace; 473 | overflow: auto; 474 | overflow-y: hidden; 475 | } 476 | 477 | td.linenos pre { 478 | padding: 5px 0px; 479 | border: 0; 480 | background-color: transparent; 481 | color: #aaa; 482 | } 483 | 484 | table.highlighttable { 485 | margin-left: 0.5em; 486 | } 487 | 488 | table.highlighttable td { 489 | padding: 0 0.5em 0 0.5em; 490 | } 491 | 492 | code { 493 | font-family: monospace; 494 | } 495 | 496 | div.code-block-caption span.caption-number { 497 | padding: 0.1em 0.3em; 498 | font-style: italic; 499 | } 500 | 501 | div.code-block-caption span.caption-text { 502 | } 503 | 504 | div.literal-block-wrapper { 505 | padding: 1em 1em 0; 506 | } 507 | 508 | div.literal-block-wrapper div.highlight { 509 | margin: 0; 510 | } 511 | 512 | code.descname { 513 | background-color: transparent; 514 | font-weight: bold; 515 | font-size: 1.2em; 516 | } 517 | 518 | code.descclassname { 519 | background-color: transparent; 520 | } 521 | 522 | code.xref, a code { 523 | background-color: transparent; 524 | font-weight: bold; 525 | } 526 | 527 | h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { 528 | background-color: transparent; 529 | } 530 | 531 | /* -- math display ---------------------------------------------------------- */ 532 | 533 | img.math { 534 | vertical-align: middle; 535 | } 536 | 537 | div.body div.math p { 538 | text-align: center; 539 | } 540 | 541 | span.eqno { 542 | float: right; 543 | } 544 | 545 | /* -- special divs --------------------------------------------------------- */ 546 | 547 | div.quotebar { 548 | background-color: #e3eff1; 549 | max-width: 250px; 550 | float: right; 551 | font-family: sans-serif; 552 | padding: 7px 7px; 553 | border: 1px solid #ccc; 554 | } 555 | div.footer { 556 | background-color: #e3eff1; 557 | padding: 3px 8px 3px 0; 558 | clear: both; 559 | font-family: sans-serif; 560 | font-size: 80%; 561 | text-align: right; 562 | } 563 | 564 | div.footer a { 565 | text-decoration: underline; 566 | } 567 | 568 | /* -- link-target ----------------------------------------------------------- */ 569 | 570 | .link-target { 571 | font-size: 80%; 572 | } 573 | 574 | table .link-target { 575 | /* Do not show links in tables, there is not enough space */ 576 | display: none; 577 | } 578 | 579 | /* -- font-face ------------------------------------------------------------- */ 580 | 581 | /* 582 | @font-face { 583 | font-family: "LiberationNarrow"; 584 | font-style: normal; 585 | font-weight: normal; 586 | src: url("res:///Data/fonts/LiberationNarrow-Regular.otf") 587 | format("opentype"); 588 | } 589 | @font-face { 590 | font-family: "LiberationNarrow"; 591 | font-style: oblique, italic; 592 | font-weight: normal; 593 | src: url("res:///Data/fonts/LiberationNarrow-Italic.otf") 594 | format("opentype"); 595 | } 596 | @font-face { 597 | font-family: "LiberationNarrow"; 598 | font-style: normal; 599 | font-weight: bold; 600 | src: url("res:///Data/fonts/LiberationNarrow-Bold.otf") 601 | format("opentype"); 602 | } 603 | @font-face { 604 | font-family: "LiberationNarrow"; 605 | font-style: oblique, italic; 606 | font-weight: bold; 607 | src: url("res:///Data/fonts/LiberationNarrow-BoldItalic.otf") 608 | format("opentype"); 609 | } 610 | */ 611 | 612 | 613 | 614 | -------------------------------------------------------------------------------- /_templates/breadcrumbs.html: -------------------------------------------------------------------------------- 1 | {# Support for Sphinx 1.3+ page_source_suffix, but don't break old builds. #} 2 | 3 | {% if page_source_suffix %} 4 | {% set suffix = page_source_suffix %} 5 | {% else %} 6 | {% set suffix = source_suffix %} 7 | {% endif %} 8 | 9 | {% if meta is defined and meta is not none %} 10 | {% set check_meta = True %} 11 | {% else %} 12 | {% set check_meta = False %} 13 | {% endif %} 14 | 15 | {% if check_meta and 'github_url' in meta %} 16 | {% set display_github = True %} 17 | {% endif %} 18 | 19 | {% if check_meta and 'bitbucket_url' in meta %} 20 | {% set display_bitbucket = True %} 21 | {% endif %} 22 | 23 | {% if check_meta and 'gitlab_url' in meta %} 24 | {% set display_gitlab = True %} 25 | {% endif %} 26 | 27 |
28 |
29 |

New book released!

30 |

Hi! I just released the alpha version of my new book; Practical Python Projects. 31 | Learn more about it 32 | on my blog. In 325+ pages, I will teach you how to implement 12 end-to-end projects. 33 | You can buy it from Feldroy.com. 34 |

35 |
36 | 77 | 78 | {% if (theme_prev_next_buttons_location == 'top' or theme_prev_next_buttons_location == 'both') and (next or prev) %} 79 | 87 | {% endif %} 88 |
89 |
90 | -------------------------------------------------------------------------------- /args_and_kwargs.rst: -------------------------------------------------------------------------------- 1 | \*args and \*\*kwargs 2 | --------------------- 3 | 4 | I have come to see that most new python programmers have a hard time 5 | figuring out the \*args and \*\*kwargs magic variables. So what are they 6 | ? First of all, let me tell you that it is not necessary to write \*args 7 | or \*\*kwargs. Only the ``*`` (asterisk) is necessary. You could have 8 | also written \*var and \*\*vars. Writing \*args and \*\*kwargs is just a 9 | convention. So now let's take a look at \*args first. 10 | 11 | Usage of \*args 12 | ^^^^^^^^^^^^^^^ 13 | 14 | \*args and \*\*kwargs are mostly used in function definitions. \*args 15 | and \*\*kwargs allow you to pass an unspecified number of arguments to a 16 | function, so when writing the function definition, you do not need to 17 | know how many arguments will be passed to your function. \*args is used to 18 | send a **non-keyworded** variable length argument list to the function. 19 | Here's an example to help you get a clear idea: 20 | 21 | .. code:: python 22 | 23 | def test_var_args(f_arg, *argv): 24 | print("first normal arg:", f_arg) 25 | for arg in argv: 26 | print("another arg through *argv:", arg) 27 | 28 | test_var_args('yasoob', 'python', 'eggs', 'test') 29 | 30 | This produces the following result: 31 | 32 | .. code:: python 33 | 34 | first normal arg: yasoob 35 | another arg through *argv: python 36 | another arg through *argv: eggs 37 | another arg through *argv: test 38 | 39 | I hope this cleared away any confusion that you had. So now let's talk 40 | about \*\*kwargs 41 | 42 | Usage of \*\*kwargs 43 | ^^^^^^^^^^^^^^^^^^^ 44 | 45 | \*\*kwargs allows you to pass **keyworded** variable length of arguments 46 | to a function. You should use \*\*kwargs if you want to handle **named 47 | arguments** in a function. Here is an example to get you going with it: 48 | 49 | .. code:: python 50 | 51 | def greet_me(**kwargs): 52 | for key, value in kwargs.items(): 53 | print("{0} = {1}".format(key, value)) 54 | 55 | >>> greet_me(name="yasoob") 56 | name = yasoob 57 | 58 | So you can see how we handled a keyworded argument list in our function. 59 | This is just the basics of \*\*kwargs and you can see how useful it is. 60 | Now let's talk about how you can use \*args and \*\*kwargs to call a 61 | function with a list or dictionary of arguments. 62 | 63 | Using \*args and \*\*kwargs to call a function 64 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 65 | 66 | So here we will see how to call a function using \*args and \*\*kwargs. 67 | Just consider that you have this little function: 68 | 69 | .. code:: python 70 | 71 | def test_args_kwargs(arg1, arg2, arg3): 72 | print("arg1:", arg1) 73 | print("arg2:", arg2) 74 | print("arg3:", arg3) 75 | 76 | Now you can use \*args or \*\*kwargs to pass arguments to this little 77 | function. Here's how to do it: 78 | 79 | .. code:: python 80 | 81 | # first with *args 82 | >>> args = ("two", 3, 5) 83 | >>> test_args_kwargs(*args) 84 | arg1: two 85 | arg2: 3 86 | arg3: 5 87 | 88 | # now with **kwargs: 89 | >>> kwargs = {"arg3": 3, "arg2": "two", "arg1": 5} 90 | >>> test_args_kwargs(**kwargs) 91 | arg1: 5 92 | arg2: two 93 | arg3: 3 94 | 95 | **Order of using \*args \*\*kwargs and formal args** 96 | 97 | So if you want to use all three of these in functions then the order is 98 | 99 | .. code:: python 100 | 101 | some_func(fargs, *args, **kwargs) 102 | 103 | When to use them? 104 | ^^^^^^^^^^^^^^^^^ 105 | 106 | It really depends on what your requirements are. The most common use 107 | case is when making function decorators (discussed in another chapter). 108 | Moreover it can be used in monkey patching as well. Monkey patching 109 | means modifying some code at runtime. Consider that you have a class 110 | with a function called ``get_info`` which calls an API and returns the 111 | response data. If we want to test it we can replace the API call with 112 | some test data. For instance: 113 | 114 | .. code:: python 115 | 116 | import someclass 117 | 118 | def get_info(self, *args): 119 | return "Test data" 120 | 121 | someclass.get_info = get_info 122 | 123 | I am sure that you can think of some other use cases as well. 124 | -------------------------------------------------------------------------------- /classes.rst: -------------------------------------------------------------------------------- 1 | Classes 2 | ------- 3 | 4 | Classes are the core of Python. They give us a lot of power but it is 5 | really easy to misuse this power. In this section I will share some 6 | obscure tricks and caveats related to ``classes`` in Python. Let's get 7 | going! 8 | 9 | 1. Instance & Class variables 10 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 11 | 12 | Most beginners and even some advanced Python programmers do not 13 | understand the distinction between instance and class variables. Their 14 | lack of understanding forces them to use these different types of 15 | variables incorrectly. Let's understand them. 16 | 17 | The basic difference is: 18 | 19 | - Instance variables are for data which is unique to every object 20 | - Class variables are for data shared between different instances of a 21 | class 22 | 23 | Let's take a look at an example: 24 | 25 | .. code:: python 26 | 27 | class Cal(object): 28 | # pi is a class variable 29 | pi = 3.142 30 | 31 | def __init__(self, radius): 32 | # self.radius is an instance variable 33 | self.radius = radius 34 | 35 | def area(self): 36 | return self.pi * (self.radius ** 2) 37 | 38 | a = Cal(32) 39 | a.area() 40 | # Output: 3217.408 41 | a.pi 42 | # Output: 3.142 43 | a.pi = 43 44 | a.pi 45 | # Output: 43 46 | 47 | b = Cal(44) 48 | b.area() 49 | # Output: 6082.912 50 | b.pi 51 | # Output: 3.142 52 | b.pi = 50 53 | b.pi 54 | # Output: 50 55 | 56 | There are not many issues while using immutable class variables. This is 57 | the major reason due to which beginners do not try to learn more about 58 | this subject because everything works! If you also believe that instance 59 | and class variables can not cause any problem if used incorrectly then 60 | check the next example. 61 | 62 | .. code:: python 63 | 64 | class SuperClass(object): 65 | superpowers = [] 66 | 67 | def __init__(self, name): 68 | self.name = name 69 | 70 | def add_superpower(self, power): 71 | self.superpowers.append(power) 72 | 73 | foo = SuperClass('foo') 74 | bar = SuperClass('bar') 75 | foo.name 76 | # Output: 'foo' 77 | 78 | bar.name 79 | # Output: 'bar' 80 | 81 | foo.add_superpower('fly') 82 | bar.superpowers 83 | # Output: ['fly'] 84 | 85 | foo.superpowers 86 | # Output: ['fly'] 87 | 88 | That is the beauty of the wrong usage of mutable class variables. To 89 | make your code safe against this kind of surprise attacks then make sure 90 | that you do not use mutable class variables. You may use them only if 91 | you know what you are doing. 92 | 93 | 2. New style classes 94 | ^^^^^^^^^^^^^^^^^^^^ 95 | 96 | New style classes were introduced in Python 2.1 but a lot of people do 97 | not know about them even now! It is so because Python also supports old 98 | style classes just to maintain backward compatibility. I have said a lot 99 | about new and old but I have not told you about the difference. Well the 100 | major difference is that: 101 | 102 | - Old base classes do not inherit from anything 103 | - New style base classes inherit from ``object`` 104 | 105 | A very basic example is: 106 | 107 | .. code:: python 108 | 109 | class OldClass(): 110 | def __init__(self): 111 | print('I am an old class') 112 | 113 | class NewClass(object): 114 | def __init__(self): 115 | print('I am a jazzy new class') 116 | 117 | old = OldClass() 118 | # Output: I am an old class 119 | 120 | new = NewClass() 121 | # Output: I am a jazzy new class 122 | 123 | This inheritance from ``object`` allows new style classes to utilize 124 | some *magic*. A major advantage is that you can employ some useful 125 | optimizations like ``__slots__``. You can use ``super()`` and 126 | descriptors and the likes. Bottom line? Always try to use new-style 127 | classes. 128 | 129 | **Note:** Python 3 only has new-style classes. It does not matter 130 | whether you subclass from ``object`` or not. However it is recommended 131 | that you still subclass from ``object``. 132 | 133 | 3. Magic Methods 134 | ^^^^^^^^^^^^^^^^ 135 | 136 | Python's classes are famous for their magic methods, commonly called 137 | **dunder** (double underscore) methods. I am going to discuss a few of 138 | them. 139 | 140 | - ``__init__`` 141 | 142 | It is a class initializer. Whenever an instance of a class is created 143 | its ``__init__`` method is called. For example: 144 | 145 | .. code:: python 146 | 147 | class GetTest(object): 148 | def __init__(self): 149 | print('Greetings!!') 150 | def another_method(self): 151 | print('I am another method which is not' 152 | ' automatically called') 153 | 154 | a = GetTest() 155 | # Output: Greetings!! 156 | 157 | a.another_method() 158 | # Output: I am another method which is not automatically 159 | # called 160 | 161 | You can see that ``__init__`` is called immediately after an instance is 162 | created. You can also pass arguments to the class during its 163 | initialization. Like this: 164 | 165 | .. code:: python 166 | 167 | class GetTest(object): 168 | def __init__(self, name): 169 | print('Greetings!! {0}'.format(name)) 170 | def another_method(self): 171 | print('I am another method which is not' 172 | ' automatically called') 173 | 174 | a = GetTest('yasoob') 175 | # Output: Greetings!! yasoob 176 | 177 | # Try creating an instance without the name arguments 178 | b = GetTest() 179 | Traceback (most recent call last): 180 | File "", line 1, in 181 | TypeError: __init__() takes exactly 2 arguments (1 given) 182 | 183 | I am sure that now you understand the ``__init__`` method. 184 | 185 | - ``__getitem__`` 186 | 187 | Implementing **getitem** in a class allows its instances to use the [] 188 | (indexer) operator. Here is an example: 189 | 190 | .. code:: python 191 | 192 | class GetTest(object): 193 | def __init__(self): 194 | self.info = { 195 | 'name':'Yasoob', 196 | 'country':'Pakistan', 197 | 'number':12345812 198 | } 199 | 200 | def __getitem__(self,i): 201 | return self.info[i] 202 | 203 | foo = GetTest() 204 | 205 | foo['name'] 206 | # Output: 'Yasoob' 207 | 208 | foo['number'] 209 | # Output: 12345812 210 | 211 | Without the ``__getitem__`` method we would have got this error: 212 | 213 | .. code:: python 214 | 215 | >>> foo['name'] 216 | 217 | Traceback (most recent call last): 218 | File "", line 1, in 219 | TypeError: 'GetTest' object has no attribute '__getitem__' 220 | 221 | .. Static, Class & Abstract methods 222 | .. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 223 | 224 | -------------------------------------------------------------------------------- /collections.rst: -------------------------------------------------------------------------------- 1 | Collections 2 | ----------- 3 | 4 | Python ships with a module that contains a number of container data 5 | types called Collections. We will talk about a few of them and discuss 6 | their usefulness. 7 | 8 | The ones which we will talk about are: 9 | 10 | - ``defaultdict`` 11 | - ``OrderedDict`` 12 | - ``Counter`` 13 | - ``deque`` 14 | - ``namedtuple`` 15 | - ``enum.Enum`` (outside of the module; Python 3.4+) 16 | 17 | ``defaultdict`` 18 | ^^^^^^^^^^^^^^^^^^^ 19 | 20 | I personally use defaultdict quite a bit. Unlike ``dict``, with 21 | ``defaultdict`` you do not need to check whether a key is present or 22 | not. So we can do: 23 | 24 | .. code:: python 25 | 26 | from collections import defaultdict 27 | 28 | colours = ( 29 | ('Yasoob', 'Yellow'), 30 | ('Ali', 'Blue'), 31 | ('Arham', 'Green'), 32 | ('Ali', 'Black'), 33 | ('Yasoob', 'Red'), 34 | ('Ahmed', 'Silver'), 35 | ) 36 | 37 | favourite_colours = defaultdict(list) 38 | 39 | for name, colour in colours: 40 | favourite_colours[name].append(colour) 41 | 42 | print(favourite_colours) 43 | 44 | # output 45 | # defaultdict(, 46 | # {'Arham': ['Green'], 47 | # 'Yasoob': ['Yellow', 'Red'], 48 | # 'Ahmed': ['Silver'], 49 | # 'Ali': ['Blue', 'Black'] 50 | # }) 51 | 52 | One other very important use case is when you are appending to nested 53 | lists inside a dictionary. If a ``key`` is not already present in the 54 | dictionary then you are greeted with a ``KeyError``. ``defaultdict`` 55 | allows us to circumvent this issue in a clever way. First let me share 56 | an example using ``dict`` which raises ``KeyError`` and then I will 57 | share a solution using ``defaultdict``. 58 | 59 | **Problem:** 60 | 61 | .. code:: python 62 | 63 | some_dict = {} 64 | some_dict['colours']['favourite'] = "yellow" 65 | # Raises KeyError: 'colours' 66 | 67 | **Solution:** 68 | 69 | .. code:: python 70 | 71 | from collections import defaultdict 72 | tree = lambda: defaultdict(tree) 73 | some_dict = tree() 74 | some_dict['colours']['favourite'] = "yellow" 75 | # Works fine 76 | 77 | You can print ``some_dict`` using ``json.dumps``. Here is some 78 | sample code: 79 | 80 | .. code:: python 81 | 82 | import json 83 | print(json.dumps(some_dict)) 84 | # Output: {"colours": {"favourite": "yellow"}} 85 | 86 | ``OrderedDict`` 87 | ^^^^^^^^^^^^^^^^^^^ 88 | 89 | ``OrderedDict`` keeps its entries sorted as they are initially inserted. 90 | Overwriting a value of an existing key doesn't change the position of 91 | that key. However, deleting and reinserting an entry moves the key to 92 | the end of the dictionary. 93 | 94 | **Problem:** 95 | 96 | .. code:: python 97 | 98 | colours = {"Red" : 198, "Green" : 170, "Blue" : 160} 99 | for key, value in colours.items(): 100 | print(key, value) 101 | # Output: 102 | # Green 170 103 | # Blue 160 104 | # Red 198 105 | # Entries are retrieved in an unpredictable order 106 | 107 | **Solution:** 108 | 109 | .. code:: python 110 | 111 | from collections import OrderedDict 112 | 113 | colours = OrderedDict([("Red", 198), ("Green", 170), ("Blue", 160)]) 114 | for key, value in colours.items(): 115 | print(key, value) 116 | # Output: 117 | # Red 198 118 | # Green 170 119 | # Blue 160 120 | # Insertion order is preserved 121 | 122 | ``Counter`` 123 | ^^^^^^^^^^^^^^^ 124 | 125 | Counter allows us to count the occurrences of a particular item. For 126 | instance it can be used to count the number of individual favourite 127 | colours: 128 | 129 | .. code:: python 130 | 131 | from collections import Counter 132 | 133 | colours = ( 134 | ('Yasoob', 'Yellow'), 135 | ('Ali', 'Blue'), 136 | ('Arham', 'Green'), 137 | ('Ali', 'Black'), 138 | ('Yasoob', 'Red'), 139 | ('Ahmed', 'Silver'), 140 | ) 141 | 142 | favs = Counter(name for name, colour in colours) 143 | print(favs) 144 | # Output: Counter({ 145 | # 'Yasoob': 2, 146 | # 'Ali': 2, 147 | # 'Arham': 1, 148 | # 'Ahmed': 1 149 | # }) 150 | 151 | We can also count the most common lines in a file using it. For example: 152 | 153 | .. code:: python 154 | 155 | with open('filename', 'rb') as f: 156 | line_count = Counter(f) 157 | print(line_count) 158 | 159 | ``deque`` 160 | ^^^^^^^^^^^^^ 161 | 162 | ``deque`` provides you with a double ended queue which means that you 163 | can append and delete elements from either side of the queue. First of 164 | all you have to import the deque module from the collections library: 165 | 166 | .. code:: python 167 | 168 | from collections import deque 169 | 170 | Now we can instantiate a deque object. 171 | 172 | .. code:: python 173 | 174 | d = deque() 175 | 176 | It works like python lists and provides you with somewhat similar 177 | methods as well. For example you can do: 178 | 179 | .. code:: python 180 | 181 | d = deque() 182 | d.append('1') 183 | d.append('2') 184 | d.append('3') 185 | 186 | print(len(d)) 187 | # Output: 3 188 | 189 | print(d[0]) 190 | # Output: '1' 191 | 192 | print(d[-1]) 193 | # Output: '3' 194 | 195 | You can pop values from both sides of the deque: 196 | 197 | .. code:: python 198 | 199 | d = deque(range(5)) 200 | print(len(d)) 201 | # Output: 5 202 | 203 | d.popleft() 204 | # Output: 0 205 | 206 | d.pop() 207 | # Output: 4 208 | 209 | print(d) 210 | # Output: deque([1, 2, 3]) 211 | 212 | We can also limit the amount of items a deque can hold. By doing this 213 | when we achieve the maximum limit of our deque it will simply pop out 214 | the items from the opposite end. It is better to explain it using an 215 | example so here you go: 216 | 217 | .. code:: python 218 | 219 | d = deque([0, 1, 2, 3, 5], maxlen=5) 220 | print(d) 221 | # Output: deque([0, 1, 2, 3, 5], maxlen=5) 222 | 223 | d.extend([6]) 224 | print(d) 225 | #Output: deque([1, 2, 3, 5, 6], maxlen=5) 226 | 227 | Now whenever you insert values after 5, the leftmost value will be 228 | popped from the list. You can also expand the list in any direction with 229 | new values: 230 | 231 | .. code:: python 232 | 233 | d = deque([1,2,3,4,5]) 234 | d.extendleft([0]) 235 | d.extend([6,7,8]) 236 | print(d) 237 | # Output: deque([0, 1, 2, 3, 4, 5, 6, 7, 8]) 238 | 239 | ``namedtuple`` 240 | ^^^^^^^^^^^^^^^^^^ 241 | 242 | You might already be acquainted with tuples. A tuple is basically 243 | a immutable list which allows you to store a sequence of values 244 | separated by commas. They are just like lists but have a few key 245 | differences. The major one is that unlike lists, **you can not 246 | reassign an item in a tuple**. In order to access the value in a 247 | tuple you use integer indexes like: 248 | 249 | .. code:: python 250 | 251 | man = ('Ali', 30) 252 | print(man[0]) 253 | # Output: Ali 254 | 255 | Well, so now what are ``namedtuples``? They turn tuples into convenient 256 | containers for simple tasks. With namedtuples you don't have to use 257 | integer indexes for accessing members of a tuple. You can think of 258 | namedtuples like dictionaries but unlike dictionaries they are 259 | immutable. 260 | 261 | .. code:: python 262 | 263 | from collections import namedtuple 264 | 265 | Animal = namedtuple('Animal', 'name age type') 266 | perry = Animal(name="perry", age=31, type="cat") 267 | 268 | print(perry) 269 | # Output: Animal(name='perry', age=31, type='cat') 270 | 271 | print(perry.name) 272 | # Output: 'perry' 273 | 274 | You can now see that we can access members of a tuple just by their 275 | name using a ``.``. Let's dissect it a little more. A named tuple has two 276 | required arguments. They are the tuple name and the tuple field\_names. 277 | In the above example our tuple name was 'Animal' and the tuple 278 | field\_names were 'name', 'age' and 'type'. Namedtuple makes your tuples 279 | **self-document**. You can easily understand what is going on by having 280 | a quick glance at your code. And as you are not bound to use integer 281 | indexes to access members of a tuple, it makes it more easy to maintain 282 | your code. Moreover, as **`namedtuple` instances do not have 283 | per-instance dictionaries**, they are lightweight and require no more 284 | memory than regular tuples. This makes them faster than dictionaries. 285 | However, do remember that as with tuples, **attributes in namedtuples 286 | are immutable**. It means that this would not work: 287 | 288 | .. code:: python 289 | 290 | from collections import namedtuple 291 | 292 | Animal = namedtuple('Animal', 'name age type') 293 | perry = Animal(name="perry", age=31, type="cat") 294 | perry.age = 42 295 | 296 | # Output: Traceback (most recent call last): 297 | # File "", line 1, in 298 | # AttributeError: can't set attribute 299 | 300 | You should use named tuples to make your code self-documenting. **They 301 | are backwards compatible with normal tuples**. It means that you can use 302 | integer indexes with namedtuples as well: 303 | 304 | .. code:: python 305 | 306 | from collections import namedtuple 307 | 308 | Animal = namedtuple('Animal', 'name age type') 309 | perry = Animal(name="perry", age=31, type="cat") 310 | print(perry[0]) 311 | # Output: perry 312 | 313 | Last but not the least, you can convert a namedtuple to a dictionary. 314 | Like this: 315 | 316 | .. code:: python 317 | 318 | from collections import namedtuple 319 | 320 | Animal = namedtuple('Animal', 'name age type') 321 | perry = Animal(name="Perry", age=31, type="cat") 322 | print(perry._asdict()) 323 | # Output: OrderedDict([('name', 'Perry'), ('age', 31), ... 324 | 325 | ``enum.Enum`` (Python 3.4+) 326 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 327 | 328 | Another useful collection is the enum object. It is available in the ``enum`` 329 | module, in Python 3.4 and up (also available as a backport in PyPI named ``enum34``.) 330 | Enums (`enumerated type `_) are 331 | basically a way to organize various things. 332 | 333 | Let’s consider the Animal namedtuple from the last example. It had a ``type`` 334 | field. The problem is, the type was a string. This poses some problems for 335 | us. What if the user types in ``Cat`` because they held the Shift key? Or 336 | ``CAT``? Or ``kitten``? 337 | 338 | Enumerations can help us avoid this problem, by not using strings. Consider 339 | this example: 340 | 341 | .. code:: python 342 | 343 | from collections import namedtuple 344 | from enum import Enum 345 | 346 | class Species(Enum): 347 | cat = 1 348 | dog = 2 349 | horse = 3 350 | aardvark = 4 351 | butterfly = 5 352 | owl = 6 353 | platypus = 7 354 | dragon = 8 355 | unicorn = 9 356 | # The list goes on and on... 357 | 358 | # But we don't really care about age, so we can use an alias. 359 | kitten = 1 360 | puppy = 2 361 | 362 | Animal = namedtuple('Animal', 'name age type') 363 | perry = Animal(name="Perry", age=31, type=Species.cat) 364 | drogon = Animal(name="Drogon", age=4, type=Species.dragon) 365 | tom = Animal(name="Tom", age=75, type=Species.cat) 366 | charlie = Animal(name="Charlie", age=2, type=Species.kitten) 367 | 368 | # And now, some tests. 369 | >>> charlie.type == tom.type 370 | True 371 | >>> charlie.type 372 | 373 | 374 | 375 | This is much less error-prone. We have to be specific, and we should use only 376 | the enumeration to name types. 377 | 378 | There are three ways to access enumeration members. For example, all three 379 | methods will get you the value for ``cat``: 380 | 381 | .. code:: python 382 | 383 | Species(1) 384 | Species['cat'] 385 | Species.cat 386 | 387 | This was just a quick drive through the ``collections`` module. Make 388 | sure you read the official documentation after reading this. 389 | -------------------------------------------------------------------------------- /comprehensions.rst: -------------------------------------------------------------------------------- 1 | Comprehensions 2 | -------------- 3 | 4 | Comprehensions are a feature of Python which I would really miss if I 5 | ever have to leave it. Comprehensions are constructs that allow 6 | sequences to be built from other sequences. Several types of 7 | comprehensions are supported in both Python 2 and Python 3: 8 | 9 | - list comprehensions 10 | - dictionary comprehensions 11 | - set comprehensions 12 | - generator comprehensions 13 | 14 | We will discuss them one by one. Once you get the hang of using ``list`` 15 | comprehensions then you can use any of them easily. 16 | 17 | ``list`` comprehensions 18 | ^^^^^^^^^^^^^^^^^^^^^^^ 19 | 20 | List comprehensions provide a short and concise way to create lists. It 21 | consists of square brackets containing an expression followed by a 22 | ``for`` clause, then zero or more ``for`` or ``if`` clauses. The 23 | expressions can be anything, meaning you can put in all kinds of objects 24 | in lists. The result would be a new list made after the evaluation of 25 | the expression in context of the ``if`` and ``for`` clauses. 26 | 27 | **Blueprint** 28 | 29 | .. code:: python 30 | 31 | variable = [out_exp for out_exp in input_list if out_exp == 2] 32 | 33 | Here is a short example: 34 | 35 | .. code:: python 36 | 37 | multiples = [i for i in range(30) if i % 3 == 0] 38 | print(multiples) 39 | # Output: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27] 40 | 41 | This can be really useful to make lists quickly. It is even preferred by 42 | some instead of the ``filter`` function. List comprehensions really 43 | shine when you want to supply a list to a method or function to make a 44 | new list by appending to it in each iteration of the ``for`` loop. For 45 | instance you would usually do something like this: 46 | 47 | .. code:: python 48 | 49 | squared = [] 50 | for x in range(10): 51 | squared.append(x**2) 52 | 53 | You can simplify it using list comprehensions. For example: 54 | 55 | .. code:: python 56 | 57 | squared = [x**2 for x in range(10)] 58 | 59 | ``dict`` comprehensions 60 | ^^^^^^^^^^^^^^^^^^^^^^^ 61 | 62 | They are used in a similar way. Here is an example which I found 63 | recently: 64 | 65 | .. code:: python 66 | 67 | mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3} 68 | 69 | mcase_frequency = { 70 | k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) 71 | for k in mcase.keys() 72 | } 73 | 74 | # mcase_frequency == {'a': 17, 'z': 3, 'b': 34} 75 | 76 | In the above example we are combining the values of keys which are same 77 | but in different typecase. I personally do not use ``dict`` 78 | comprehensions a lot. You can also quickly switch keys and values of a dictionary: 79 | 80 | .. code:: python 81 | 82 | {v: k for k, v in some_dict.items()} 83 | 84 | ``set`` comprehensions 85 | ^^^^^^^^^^^^^^^^^^^^^^ 86 | 87 | They are also similar to list comprehensions. The only difference is 88 | that they use braces ``{}``. Here is an example: 89 | 90 | .. code:: python 91 | 92 | squared = {x**2 for x in [1, 1, 2]} 93 | print(squared) 94 | # Output: {1, 4} 95 | 96 | ``generator`` comprehensions 97 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 98 | 99 | They are also similar to list comprehensions. The only difference is that they don't allocate memory for the whole list but generate one item at a time, thus more memory efficient. 100 | 101 | .. code:: python 102 | 103 | multiples_gen = (i for i in range(30) if i % 3 == 0) 104 | print(multiples_gen) 105 | # Output: at 0x7fdaa8e407d8> 106 | for x in multiples_gen: 107 | print(x) 108 | # Outputs numbers 109 | -------------------------------------------------------------------------------- /conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Python Tips documentation build configuration file, created by 4 | # sphinx-quickstart on Tue Apr 28 00:44:47 2015. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | import sphinx_rtd_theme 16 | 17 | # If extensions (or modules to document with autodoc) are in another directory, 18 | # add these directories to sys.path here. If the directory is relative to the 19 | # documentation root, use os.path.abspath to make it absolute, like shown here. 20 | #sys.path.insert(0, os.path.abspath('.')) 21 | 22 | # -- General configuration ----------------------------------------------------- 23 | 24 | # If your documentation needs a minimal Sphinx version, state it here. 25 | #needs_sphinx = '1.0' 26 | 27 | # Add any Sphinx extension module names here, as strings. They can be extensions 28 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 29 | extensions = ['sphinx.ext.todo'] 30 | 31 | # Add any paths that contain templates here, relative to this directory. 32 | templates_path = ['_templates'] 33 | 34 | # The suffix of source filenames. 35 | source_suffix = '.rst' 36 | 37 | # The encoding of source files. 38 | #source_encoding = 'utf-8-sig' 39 | 40 | # The master toctree document. 41 | master_doc = 'index' 42 | 43 | # General information about the project. 44 | project = u'Python Tips' 45 | copyright = u'2017, Muhammad Yasoob Ullah Khalid' 46 | 47 | # The version info for the project you're documenting, acts as replacement for 48 | # |version| and |release|, also used in various other places throughout the 49 | # built documents. 50 | # 51 | # The short X.Y version. 52 | version = '0.1' 53 | # The full version, including alpha/beta/rc tags. 54 | release = '0.1' 55 | 56 | # The language for content autogenerated by Sphinx. Refer to documentation 57 | # for a list of supported languages. 58 | #language = None 59 | 60 | # There are two options for replacing |today|: either, you set today to some 61 | # non-false value, then it is used: 62 | #today = '' 63 | # Else, today_fmt is used as the format for a strftime call. 64 | #today_fmt = '%B %d, %Y' 65 | 66 | # List of patterns, relative to source directory, that match files and 67 | # directories to ignore when looking for source files. 68 | exclude_patterns = ['_build'] 69 | 70 | # The reST default role (used for this markup: `text`) to use for all documents. 71 | #default_role = None 72 | 73 | # If true, '()' will be appended to :func: etc. cross-reference text. 74 | #add_function_parentheses = True 75 | 76 | # If true, the current module name will be prepended to all description 77 | # unit titles (such as .. function::). 78 | #add_module_names = True 79 | 80 | # If true, sectionauthor and moduleauthor directives will be shown in the 81 | # output. They are ignored by default. 82 | #show_authors = False 83 | 84 | # The name of the Pygments (syntax highlighting) style to use. 85 | pygments_style = 'sphinx' 86 | 87 | # A list of ignored prefixes for module index sorting. 88 | #modindex_common_prefix = [] 89 | 90 | # If true, keep warnings as "system message" paragraphs in the built documents. 91 | #keep_warnings = False 92 | 93 | 94 | # -- Options for HTML output --------------------------------------------------- 95 | 96 | # The theme to use for HTML and HTML Help pages. See the documentation for 97 | # a list of builtin themes. 98 | html_theme = 'default' 99 | 100 | # Theme options are theme-specific and customize the look and feel of a theme 101 | # further. For a list of options available for each theme, see the 102 | # documentation. 103 | #html_theme_options = {} 104 | 105 | # Add any paths that contain custom themes here, relative to this directory. 106 | #html_theme_path = [] 107 | 108 | # The name for this set of Sphinx documents. If None, it defaults to 109 | # " v documentation". 110 | #html_title = None 111 | 112 | # A shorter title for the navigation bar. Default is the same as html_title. 113 | #html_short_title = None 114 | 115 | # The name of an image file (relative to this directory) to place at the top 116 | # of the sidebar. 117 | #html_logo = None 118 | 119 | # The name of an image file (within the static path) to use as favicon of the 120 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 121 | # pixels large. 122 | #html_favicon = None 123 | 124 | # Add any paths that contain custom static files (such as style sheets) here, 125 | # relative to this directory. They are copied after the builtin static files, 126 | # so a file named "default.css" will overwrite the builtin "default.css". 127 | html_static_path = ['_static'] 128 | 129 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 130 | # using the given strftime format. 131 | #html_last_updated_fmt = '%b %d, %Y' 132 | 133 | # If true, SmartyPants will be used to convert quotes and dashes to 134 | # typographically correct entities. 135 | #html_use_smartypants = True 136 | 137 | # Custom sidebar templates, maps document names to template names. 138 | #html_sidebars = {} 139 | 140 | # Additional templates that should be rendered to pages, maps page names to 141 | # template names. 142 | #html_additional_pages = {} 143 | 144 | # If false, no module index is generated. 145 | #html_domain_indices = True 146 | 147 | # If false, no index is generated. 148 | #html_use_index = True 149 | 150 | # If true, the index is split into individual pages for each letter. 151 | #html_split_index = False 152 | 153 | # If true, links to the reST sources are added to the pages. 154 | #html_show_sourcelink = True 155 | 156 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 157 | html_show_sphinx = False 158 | 159 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 160 | #html_show_copyright = True 161 | 162 | # If true, an OpenSearch description file will be output, and all pages will 163 | # contain a tag referring to it. The value of this option must be the 164 | # base URL from which the finished HTML is served. 165 | #html_use_opensearch = '' 166 | 167 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 168 | #html_file_suffix = None 169 | 170 | # Output file base name for HTML help builder. 171 | htmlhelp_basename = 'PythonTipsdoc' 172 | 173 | 174 | # -- Options for LaTeX output -------------------------------------------------- 175 | 176 | latex_elements = { 177 | 'fontpkg': r'\usepackage{mathpazo}', 178 | 'papersize': 'a4paper', 179 | 'pointsize': '12pt', 180 | 'classoptions': ',oneside', 181 | 'babel': r'\usepackage[english]{babel}', 182 | 'preamble': r'\usepackage{flaskstyle}' 183 | } 184 | latex_use_parts = True 185 | 186 | # Grouping the document tree into LaTeX files. List of tuples 187 | # (source start file, target name, title, author, documentclass [howto/manual]). 188 | latex_documents = [ 189 | ('index', 'PythonTips.tex', u'Python Tips', 190 | u'Muhammad Yasoob Ullah Khalid', 'manual'), 191 | ] 192 | 193 | # The name of an image file (relative to this directory) to place at the top of 194 | # the title page. 195 | latex_logo = '_static/cover.pdf' 196 | latex_additional_files = ['flaskstyle.sty', '_static/cover.pdf'] 197 | 198 | # For "manual" documents, if this is true, then toplevel headings are parts, 199 | # not chapters. 200 | #latex_use_parts = False 201 | 202 | # If true, show page references after internal links. 203 | #latex_show_pagerefs = False 204 | 205 | # If true, show URL addresses after external links. 206 | #latex_show_urls = False 207 | 208 | # Documents to append as an appendix to all manuals. 209 | #latex_appendices = [] 210 | 211 | # If false, no module index is generated. 212 | #latex_domain_indices = True 213 | 214 | 215 | # -- Options for manual page output -------------------------------------------- 216 | 217 | # One entry per manual page. List of tuples 218 | # (source start file, name, description, authors, manual section). 219 | man_pages = [ 220 | ('index', 'pythontips', u'Python Tips', 221 | [u'Muhammad Yasoob Ullah Khalid'], 1) 222 | ] 223 | 224 | # If true, show URL addresses after external links. 225 | #man_show_urls = False 226 | 227 | 228 | # -- Options for Texinfo output ------------------------------------------------ 229 | 230 | # Grouping the document tree into Texinfo files. List of tuples 231 | # (source start file, target name, title, author, 232 | # dir menu entry, description, category) 233 | texinfo_documents = [ 234 | ('index', 'PythonTips', u'Python Tips', 235 | u'Muhammad Yasoob Ullah Khalid', 'PythonTips', 'One line description of project.', 236 | 'Miscellaneous'), 237 | ] 238 | 239 | # Documents to append as an appendix to all manuals. 240 | #texinfo_appendices = [] 241 | 242 | # If false, no module index is generated. 243 | #texinfo_domain_indices = True 244 | 245 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 246 | #texinfo_show_urls = 'footnote' 247 | 248 | # If true, do not generate a @detailmenu in the "Top" node's menu. 249 | #texinfo_no_detailmenu = False 250 | 251 | 252 | # -- Options for Epub output --------------------------------------------------- 253 | 254 | # Bibliographic Dublin Core info. 255 | epub_title = u'Python Tips' 256 | epub_author = u'Muhammad Yasoob Ullah Khalid' 257 | epub_publisher = u'Muhammad Yasoob Ullah Khalid' 258 | epub_copyright = u'2017, Muhammad Yasoob Ullah Khalid' 259 | 260 | 261 | #epub_theme = 'epub' 262 | 263 | # The language of the text. It defaults to the language option 264 | # or en if the language is not set. 265 | #epub_language = '' 266 | 267 | # The scheme of the identifier. Typical schemes are ISBN or URL. 268 | #epub_scheme = '' 269 | 270 | # The unique identifier of the text. This can be a ISBN number 271 | # or the project homepage. 272 | #epub_identifier = '' 273 | 274 | # A unique identification for the text. 275 | #epub_uid = '' 276 | 277 | # A tuple containing the cover image and cover page html template filenames. 278 | epub_cover = ('_static/cover.png', 'epub-cover.html') 279 | 280 | # A sequence of (type, uri, title) tuples for the guide element of content.opf. 281 | #epub_guide = () 282 | 283 | # HTML files that should be inserted before the pages created by sphinx. 284 | # The format is a list of tuples containing the path and title. 285 | #epub_pre_files = [] 286 | 287 | # HTML files shat should be inserted after the pages created by sphinx. 288 | # The format is a list of tuples containing the path and title. 289 | #epub_post_files = [] 290 | 291 | # A list of files that should not be packed into the epub file. 292 | #epub_exclude_files = [] 293 | 294 | # The depth of the table of contents in toc.ncx. 295 | #epub_tocdepth = 3 296 | 297 | # Allow duplicate toc entries. 298 | #epub_tocdup = True 299 | 300 | # Fix unsupported image types using the PIL. 301 | #epub_fix_images = False 302 | 303 | # Scale large images. 304 | #epub_max_image_width = 0 305 | 306 | # If 'no', URL addresses will not be shown. 307 | #epub_show_urls = 'inline' 308 | 309 | # If false, no index is generated. 310 | epub_use_index = False 311 | 312 | sys.path.append(os.path.abspath('_themes')) 313 | #html_theme_path = ['_themes'] 314 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 315 | html_theme = 'sphinx_rtd_theme' 316 | 317 | -------------------------------------------------------------------------------- /context_managers.rst: -------------------------------------------------------------------------------- 1 | Context Managers 2 | ---------------- 3 | 4 | Context managers allow you to allocate and release resources precisely 5 | when you want to. The most widely used example of context managers is 6 | the ``with`` statement. Suppose you have two related operations which 7 | you’d like to execute as a pair, with a block of code in between. 8 | Context managers allow you to do specifically that. For example: 9 | 10 | .. code:: python 11 | 12 | with open('some_file', 'w') as opened_file: 13 | opened_file.write('Hola!') 14 | 15 | The above code opens the file, writes some data to it and then closes 16 | it. If an error occurs while writing the data to the file, it tries to 17 | close it. The above code is equivalent to: 18 | 19 | .. code:: python 20 | 21 | file = open('some_file', 'w') 22 | try: 23 | file.write('Hola!') 24 | finally: 25 | file.close() 26 | 27 | While comparing it to the first example we can see that a lot of 28 | boilerplate code is eliminated just by using ``with``. The main 29 | advantage of using a ``with`` statement is that it makes sure our file 30 | is closed without paying attention to how the nested block exits. 31 | 32 | A common use case of context managers is locking and unlocking resources 33 | and closing opened files (as I have already shown you). 34 | 35 | Let's see how we can implement our own Context Manager. This should allow 36 | us to understand exactly what's going on behind the scenes. 37 | 38 | Implementing a Context Manager as a Class: 39 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 40 | 41 | At the very least a context manager has an ``__enter__`` and 42 | ``__exit__`` method defined. Let's make our own file-opening Context 43 | Manager and learn the basics. 44 | 45 | .. code:: python 46 | 47 | class File(object): 48 | def __init__(self, file_name, method): 49 | self.file_obj = open(file_name, method) 50 | def __enter__(self): 51 | return self.file_obj 52 | def __exit__(self, type, value, traceback): 53 | self.file_obj.close() 54 | 55 | Just by defining ``__enter__`` and ``__exit__`` methods we can use our new class in 56 | a ``with`` statement. Let's try: 57 | 58 | .. code:: python 59 | 60 | with File('demo.txt', 'w') as opened_file: 61 | opened_file.write('Hola!') 62 | 63 | Our ``__exit__`` method accepts three arguments. They are required by 64 | every ``__exit__`` method which is a part of a Context Manager class. 65 | Let's talk about what happens under-the-hood. 66 | 67 | 1. The ``with`` statement stores the ``__exit__`` method of the ``File`` 68 | class. 69 | 2. It calls the ``__enter__`` method of the ``File`` class. 70 | 3. The ``__enter__`` method opens the file and returns it. 71 | 4. The opened file handle is passed to ``opened_file``. 72 | 5. We write to the file using ``.write()``. 73 | 6. The ``with`` statement calls the stored ``__exit__`` method. 74 | 7. The ``__exit__`` method closes the file. 75 | 76 | Handling Exceptions 77 | ^^^^^^^^^^^^^^^^^^^ 78 | 79 | We did not talk about the ``type``, ``value`` and ``traceback`` 80 | arguments of the ``__exit__`` method. Between the 4th and 6th step, if 81 | an exception occurs, Python passes the type, value and traceback of the 82 | exception to the ``__exit__`` method. It allows the ``__exit__`` method 83 | to decide how to close the file and if any further steps are required. 84 | In our case we are not paying any attention to them. 85 | 86 | What if our file object raises an exception? We might be trying to 87 | access a method on the file object which it does not supports. For 88 | instance: 89 | 90 | .. code:: python 91 | 92 | with File('demo.txt', 'w') as opened_file: 93 | opened_file.undefined_function('Hola!') 94 | 95 | Let's list the steps which are taken by the ``with`` statement when 96 | an error is encountered: 97 | 98 | 1. It passes the type, value and traceback of the error to the 99 | ``__exit__`` method. 100 | 2. It allows the ``__exit__`` method to handle the exception. 101 | 3. If ``__exit__`` returns ``True`` then the exception was gracefully 102 | handled. 103 | 4. If anything other than ``True`` is returned by the ``__exit__`` method then 104 | the exception is raised by the ``with`` statement. 105 | 106 | In our case the ``__exit__`` method returns ``None`` (when no return 107 | statement is encountered then the method returns ``None``). Therefore, 108 | the ``with`` statement raises the exception: 109 | 110 | .. code:: python 111 | 112 | Traceback (most recent call last): 113 | File "", line 2, in 114 | AttributeError: 'file' object has no attribute 'undefined_function' 115 | 116 | Let's try handling the exception in the ``__exit__`` method: 117 | 118 | .. code:: python 119 | 120 | class File(object): 121 | def __init__(self, file_name, method): 122 | self.file_obj = open(file_name, method) 123 | def __enter__(self): 124 | return self.file_obj 125 | def __exit__(self, type, value, traceback): 126 | print("Exception has been handled") 127 | self.file_obj.close() 128 | return True 129 | 130 | with File('demo.txt', 'w') as opened_file: 131 | opened_file.undefined_function() 132 | 133 | # Output: Exception has been handled 134 | 135 | Our ``__exit__`` method returned ``True``, therefore no exception was raised 136 | by the ``with`` statement. 137 | 138 | This is not the only way to implement Context Managers. There is another 139 | way and we will be looking at it in the next section. 140 | 141 | Implementing a Context Manager as a Generator 142 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 143 | 144 | We can also implement Context Managers using decorators and generators. 145 | Python has a contextlib module for this very purpose. Instead of a 146 | class, we can implement a Context Manager using a generator function. 147 | Let's see a basic, useless example: 148 | 149 | .. code:: python 150 | 151 | from contextlib import contextmanager 152 | 153 | @contextmanager 154 | def open_file(name): 155 | f = open(name, 'w') 156 | try: 157 | yield f 158 | finally: 159 | f.close() 160 | 161 | Okay! This way of implementing Context Managers appear to be more 162 | intuitive and easy. However, this method requires some knowledge about 163 | generators, yield and decorators. In this example we have not caught any 164 | exceptions which might occur. It works in mostly the same way as the 165 | previous method. 166 | 167 | Let's dissect this method a little. 168 | 169 | 1. Python encounters the ``yield`` keyword. Due to this it creates a 170 | generator instead of a normal function. 171 | 2. Due to the decoration, contextmanager is called with the function 172 | name (``open_file``) as its argument. 173 | 3. The ``contextmanager`` decorator returns the generator wrapped by the 174 | ``GeneratorContextManager`` object. 175 | 4. The ``GeneratorContextManager`` is assigned to the ``open_file`` 176 | function. Therefore, when we later call the ``open_file`` function, we 177 | are actually calling the ``GeneratorContextManager`` object. 178 | 179 | So now that we know all this, we can use the newly generated Context 180 | Manager like this: 181 | 182 | .. code:: python 183 | 184 | with open_file('some_file') as f: 185 | f.write('hola!') 186 | -------------------------------------------------------------------------------- /coroutines.rst: -------------------------------------------------------------------------------- 1 | Coroutines 2 | ---------- 3 | 4 | Coroutines are similar to generators with a few differences. The main 5 | differences are: 6 | 7 | - generators are data producers 8 | - coroutines are data consumers 9 | 10 | First of all let's review the generator creation process. We can make 11 | generators like this: 12 | 13 | .. code:: python 14 | 15 | def fib(): 16 | a, b = 0, 1 17 | while True: 18 | yield a 19 | a, b = b, a+b 20 | 21 | We then commonly use it in a ``for`` loop like this: 22 | 23 | .. code:: python 24 | 25 | for i in fib(): 26 | print(i) 27 | 28 | It is fast and does not put a lot of pressure on memory because it 29 | **generates** the values on the fly rather than storing them in a list. 30 | Now, if we use ``yield`` in the above example, more generally, we get a 31 | coroutine. Coroutines consume values which are sent to it. A very basic 32 | example would be a ``grep`` alternative in Python: 33 | 34 | .. code:: python 35 | 36 | def grep(pattern): 37 | print("Searching for", pattern) 38 | while True: 39 | line = (yield) 40 | if pattern in line: 41 | print(line) 42 | 43 | Wait! What does ``yield`` return? Well we have turned it into a 44 | coroutine. It does not contain any value initially, instead we supply it 45 | values externally. We supply values by using the ``.send()`` method. 46 | Here is an example: 47 | 48 | .. code:: python 49 | 50 | search = grep('coroutine') 51 | next(search) 52 | # Output: Searching for coroutine 53 | search.send("I love you") 54 | search.send("Don't you love me?") 55 | search.send("I love coroutines instead!") 56 | # Output: I love coroutines instead! 57 | 58 | The sent values are accessed by ``yield``. Why did we run ``next()``? It is 59 | required in order to start the coroutine. Just like ``generators``, coroutines do not 60 | start the function immediately. Instead they run it in response to the 61 | ``__next__()`` and ``.send()`` methods. Therefore, you have to run 62 | ``next()`` so that the execution advances to the ``yield`` expression. 63 | 64 | We can close a coroutine by calling the ``.close()`` method: 65 | 66 | .. code:: python 67 | 68 | search = grep('coroutine') 69 | # ... 70 | search.close() 71 | 72 | There is a lot more to ``coroutines``. I suggest you check out `this 73 | awesome 74 | presentation `__ by 75 | David Beazley. 76 | -------------------------------------------------------------------------------- /debugging.rst: -------------------------------------------------------------------------------- 1 | Debugging 2 | --------- 3 | 4 | Debugging is also something which once mastered can greatly enhance your 5 | bug hunting skills. Most newcomers neglect the importance of the 6 | Python debugger (``pdb``). In this section I am going to tell you only a 7 | few important commands. You can learn more about it from the official 8 | documentation. 9 | 10 | **Running from the command line** 11 | 12 | You can run a script from the command line using the Python debugger. 13 | Here is an example: 14 | 15 | .. code:: python 16 | 17 | $ python -m pdb my_script.py 18 | 19 | It would cause the debugger to stop the execution on the first statement 20 | it finds. This is helpful if your script is short. You can then inspect 21 | the variables and continue execution line-by-line. 22 | 23 | **Running from inside a script** 24 | 25 | You can set break points in the script itself so that you can inspect 26 | the variables and stuff at particular points. This is possible using the 27 | ``pdb.set_trace()`` method. Here is an example: 28 | 29 | .. code:: python 30 | 31 | import pdb 32 | 33 | def make_bread(): 34 | pdb.set_trace() 35 | return "I don't have time" 36 | 37 | print(make_bread()) 38 | 39 | Try running the above script after saving it. You would enter the 40 | debugger as soon as you run it. Now it's time to learn some of the 41 | commands of the debugger. 42 | 43 | **Commands:** 44 | 45 | - ``c``: continue execution 46 | - ``w``: shows the context of the current line it is executing. 47 | - ``a``: print the argument list of the current function 48 | - ``s``: Execute the current line and stop at the first possible 49 | occasion. 50 | - ``n``: Continue execution until the next line in the current function 51 | is reached or it returns. 52 | 53 | The difference between ``n``\ ext and ``s``\ tep is that step stops 54 | inside a called function, while next executes called functions at 55 | (nearly) full speed, only stopping at the next line in the current 56 | function. 57 | 58 | These are just a few commands. ``pdb`` also supports post mortem. It is 59 | also a really handy function. I would highly suggest you to look at the 60 | official documentation and learn more about it. 61 | 62 | **Note:** 63 | 64 | It might seem unintuitive to use `pdb.set_trace()` if you are new to this. Fortunately, if you are using Python 3.7+ then you can simply use the `breakpoint()` [built-in function](https://docs.python.org/3/library/functions.html#breakpoint). It automatically imports `pdb` and calls `pdb.set_trace()`. 65 | -------------------------------------------------------------------------------- /decorators.rst: -------------------------------------------------------------------------------- 1 | Decorators 2 | ---------- 3 | 4 | Decorators are a significant part of Python. In simple words: they are 5 | functions which modify the functionality of other functions. They help 6 | to make our code shorter and more Pythonic. Most beginners do not 7 | know where to use them so I am going to share some areas where 8 | decorators can make your code more concise. 9 | 10 | First, let's discuss how to write your own decorator. 11 | 12 | It is perhaps one of the most difficult concepts to grasp. We will take 13 | it one step at a time so that you can fully understand it. 14 | 15 | Everything in Python is an object: 16 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 17 | 18 | First of all let's understand functions in Python: 19 | 20 | .. code:: python 21 | 22 | def hi(name="yasoob"): 23 | return "hi " + name 24 | 25 | print(hi()) 26 | # output: 'hi yasoob' 27 | 28 | # We can even assign a function to a variable like 29 | greet = hi 30 | # We are not using parentheses here because we are not calling the function hi 31 | # instead we are just putting it into the greet variable. Let's try to run this 32 | 33 | print(greet()) 34 | # output: 'hi yasoob' 35 | 36 | # Let's see what happens if we delete the old hi function! 37 | del hi 38 | print(hi()) 39 | #outputs: NameError 40 | 41 | print(greet()) 42 | #outputs: 'hi yasoob' 43 | 44 | Defining functions within functions: 45 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 46 | 47 | So those are the basics when it comes to functions. Let's take your 48 | knowledge one step further. In Python we can define functions inside 49 | other functions: 50 | 51 | .. code:: python 52 | 53 | def hi(name="yasoob"): 54 | print("now you are inside the hi() function") 55 | 56 | def greet(): 57 | return "now you are in the greet() function" 58 | 59 | def welcome(): 60 | return "now you are in the welcome() function" 61 | 62 | print(greet()) 63 | print(welcome()) 64 | print("now you are back in the hi() function") 65 | 66 | hi() 67 | #output:now you are inside the hi() function 68 | # now you are in the greet() function 69 | # now you are in the welcome() function 70 | # now you are back in the hi() function 71 | 72 | # This shows that whenever you call hi(), greet() and welcome() 73 | # are also called. However the greet() and welcome() functions 74 | # are not available outside the hi() function e.g: 75 | 76 | greet() 77 | #outputs: NameError: name 'greet' is not defined 78 | 79 | So now we know that we can define functions in other functions. In 80 | other words: we can make nested functions. Now you need to learn one 81 | more thing, that functions can return functions too. 82 | 83 | Returning functions from within functions: 84 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 85 | 86 | It is not necessary to execute a function within another function, we 87 | can return it as an output as well: 88 | 89 | .. code:: python 90 | 91 | def hi(name="yasoob"): 92 | def greet(): 93 | return "now you are in the greet() function" 94 | 95 | def welcome(): 96 | return "now you are in the welcome() function" 97 | 98 | if name == "yasoob": 99 | return greet 100 | else: 101 | return welcome 102 | 103 | a = hi() 104 | print(a) 105 | #outputs: 106 | 107 | #This clearly shows that `a` now points to the greet() function in hi() 108 | #Now try this 109 | 110 | print(a()) 111 | #outputs: now you are in the greet() function 112 | 113 | Just take a look at the code again. In the ``if/else`` clause we are 114 | returning ``greet`` and ``welcome``, not ``greet()`` and ``welcome()``. 115 | Why is that? It's because when you put a pair of parentheses after it, the 116 | function gets executed; whereas if you don't put parenthesis after it, 117 | then it can be passed around and can be assigned to other variables 118 | without executing it. Did you get it? Let me explain it in a little bit 119 | more detail. When we write ``a = hi()``, ``hi()`` gets executed and 120 | because the name is yasoob by default, the function ``greet`` is returned. 121 | If we change the statement to ``a = hi(name = "ali")`` then the ``welcome`` 122 | function will be returned. We can also do print ``hi()()`` which outputs 123 | *now you are in the greet() function*. 124 | 125 | Giving a function as an argument to another function: 126 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 127 | 128 | .. code:: python 129 | 130 | def hi(): 131 | return "hi yasoob!" 132 | 133 | def doSomethingBeforeHi(func): 134 | print("I am doing some boring work before executing hi()") 135 | print(func()) 136 | 137 | doSomethingBeforeHi(hi) 138 | #outputs:I am doing some boring work before executing hi() 139 | # hi yasoob! 140 | 141 | Now you have all the required knowledge to learn what decorators really 142 | are. Decorators let you execute code before and after a function. 143 | 144 | Writing your first decorator: 145 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 146 | 147 | In the last example we actually made a decorator! Let's modify the 148 | previous decorator and make a little bit more usable program: 149 | 150 | .. code:: python 151 | 152 | def a_new_decorator(a_func): 153 | 154 | def wrapTheFunction(): 155 | print("I am doing some boring work before executing a_func()") 156 | 157 | a_func() 158 | 159 | print("I am doing some boring work after executing a_func()") 160 | 161 | return wrapTheFunction 162 | 163 | def a_function_requiring_decoration(): 164 | print("I am the function which needs some decoration to remove my foul smell") 165 | 166 | a_function_requiring_decoration() 167 | #outputs: "I am the function which needs some decoration to remove my foul smell" 168 | 169 | a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration) 170 | #now a_function_requiring_decoration is wrapped by wrapTheFunction() 171 | 172 | a_function_requiring_decoration() 173 | #outputs:I am doing some boring work before executing a_func() 174 | # I am the function which needs some decoration to remove my foul smell 175 | # I am doing some boring work after executing a_func() 176 | 177 | Did you get it? We just applied the previously learned principles. This 178 | is exactly what the decorators do in Python! They wrap a function and 179 | modify its behaviour in one way or another. Now you might be 180 | wondering why we did not use the @ anywhere in our code? That is just a 181 | short way of making up a decorated function. Here is how we could have 182 | run the previous code sample using @. 183 | 184 | .. code:: python 185 | 186 | @a_new_decorator 187 | def a_function_requiring_decoration(): 188 | """Hey you! Decorate me!""" 189 | print("I am the function which needs some decoration to " 190 | "remove my foul smell") 191 | 192 | a_function_requiring_decoration() 193 | #outputs: I am doing some boring work before executing a_func() 194 | # I am the function which needs some decoration to remove my foul smell 195 | # I am doing some boring work after executing a_func() 196 | 197 | #the @a_new_decorator is just a short way of saying: 198 | a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration) 199 | 200 | I hope you now have a basic understanding of how decorators work in 201 | Python. Now there is one problem with our code. If we run: 202 | 203 | .. code:: python 204 | 205 | print(a_function_requiring_decoration.__name__) 206 | # Output: wrapTheFunction 207 | 208 | That's not what we expected! Its name is 209 | "a\_function\_requiring\_decoration". Well, our function was replaced by 210 | wrapTheFunction. It overrode the name and docstring of our function. 211 | Luckily, Python provides us a simple function to solve this problem and 212 | that is ``functools.wraps``. Let's modify our previous example to use 213 | ``functools.wraps``: 214 | 215 | .. code:: python 216 | 217 | from functools import wraps 218 | 219 | def a_new_decorator(a_func): 220 | @wraps(a_func) 221 | def wrapTheFunction(): 222 | print("I am doing some boring work before executing a_func()") 223 | a_func() 224 | print("I am doing some boring work after executing a_func()") 225 | return wrapTheFunction 226 | 227 | @a_new_decorator 228 | def a_function_requiring_decoration(): 229 | """Hey yo! Decorate me!""" 230 | print("I am the function which needs some decoration to " 231 | "remove my foul smell") 232 | 233 | print(a_function_requiring_decoration.__name__) 234 | # Output: a_function_requiring_decoration 235 | 236 | Now that is much better. Let's move on and learn some use-cases of 237 | decorators. 238 | 239 | **Blueprint:** 240 | 241 | .. code:: python 242 | 243 | from functools import wraps 244 | def decorator_name(f): 245 | @wraps(f) 246 | def decorated(*args, **kwargs): 247 | if not can_run: 248 | return "Function will not run" 249 | return f(*args, **kwargs) 250 | return decorated 251 | 252 | @decorator_name 253 | def func(): 254 | return("Function is running") 255 | 256 | can_run = True 257 | print(func()) 258 | # Output: Function is running 259 | 260 | can_run = False 261 | print(func()) 262 | # Output: Function will not run 263 | 264 | Note: ``@wraps`` takes a function to be decorated and adds the 265 | functionality of copying over the function name, docstring, arguments 266 | list, etc. This allows us to access the pre-decorated function's properties 267 | in the decorator. 268 | 269 | Use-cases: 270 | ~~~~~~~~~~ 271 | 272 | Now let's take a look at the areas where decorators really shine and 273 | their usage makes something really easy to manage. 274 | 275 | Authorization 276 | ~~~~~~~~~~~~~ 277 | 278 | Decorators can help to check whether someone is authorized to use an 279 | endpoint in a web application. They are extensively used in Flask web 280 | framework and Django. Here is an example to employ decorator based 281 | authentication: 282 | 283 | **Example :** 284 | 285 | .. code:: python 286 | 287 | from functools import wraps 288 | 289 | def requires_auth(f): 290 | @wraps(f) 291 | def decorated(*args, **kwargs): 292 | auth = request.authorization 293 | if not auth or not check_auth(auth.username, auth.password): 294 | authenticate() 295 | return f(*args, **kwargs) 296 | return decorated 297 | 298 | Logging 299 | ~~~~~~~ 300 | 301 | Logging is another area where the decorators shine. Here is an example: 302 | 303 | .. code:: python 304 | 305 | from functools import wraps 306 | 307 | def logit(func): 308 | @wraps(func) 309 | def with_logging(*args, **kwargs): 310 | print(func.__name__ + " was called") 311 | return func(*args, **kwargs) 312 | return with_logging 313 | 314 | @logit 315 | def addition_func(x): 316 | """Do some math.""" 317 | return x + x 318 | 319 | 320 | result = addition_func(4) 321 | # Output: addition_func was called 322 | 323 | I am sure you are already thinking about some clever uses of decorators. 324 | 325 | Decorators with Arguments 326 | ^^^^^^^^^^^^^^^^^^^^^^^^^ 327 | 328 | Come to think of it, isn't ``@wraps`` also a decorator? But, it takes an 329 | argument like any normal function can do. So, why can't we do that too? 330 | 331 | This is because when you use the ``@my_decorator`` syntax, you are 332 | applying a wrapper function with a single function as a parameter. 333 | Remember, everything in Python is an object, and this includes 334 | functions! With that in mind, we can write a function that returns 335 | a wrapper function. 336 | 337 | Nesting a Decorator Within a Function 338 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 339 | 340 | Let's go back to our logging example, and create a wrapper which lets 341 | us specify a logfile to output to. 342 | 343 | .. code:: python 344 | 345 | from functools import wraps 346 | 347 | def logit(logfile='out.log'): 348 | def logging_decorator(func): 349 | @wraps(func) 350 | def wrapped_function(*args, **kwargs): 351 | log_string = func.__name__ + " was called" 352 | print(log_string) 353 | # Open the logfile and append 354 | with open(logfile, 'a') as opened_file: 355 | # Now we log to the specified logfile 356 | opened_file.write(log_string + '\n') 357 | return func(*args, **kwargs) 358 | return wrapped_function 359 | return logging_decorator 360 | 361 | @logit() 362 | def myfunc1(): 363 | pass 364 | 365 | myfunc1() 366 | # Output: myfunc1 was called 367 | # A file called out.log now exists, with the above string 368 | 369 | @logit(logfile='func2.log') 370 | def myfunc2(): 371 | pass 372 | 373 | myfunc2() 374 | # Output: myfunc2 was called 375 | # A file called func2.log now exists, with the above string 376 | 377 | Decorator Classes 378 | ~~~~~~~~~~~~~~~~~ 379 | 380 | Now we have our logit decorator in production, but when some parts 381 | of our application are considered critical, failure might be 382 | something that needs more immediate attention. Let's say sometimes 383 | you want to just log to a file. Other times you want an email sent, 384 | so the problem is brought to your attention, and still keep a log 385 | for your own records. This is a case for using inheritence, but 386 | so far we've only seen functions being used to build decorators. 387 | 388 | Luckily, classes can also be used to build decorators. So, let's 389 | rebuild logit as a class instead of a function. 390 | 391 | .. code:: python 392 | 393 | class logit(object): 394 | 395 |        _logfile = 'out.log' 396 |     397 | def __init__(self, func): 398 | self.func = func 399 | 400 |        def __call__(self, *args): 401 |            log_string = self.func.__name__ + " was called" 402 | print(log_string) 403 | # Open the logfile and append 404 |            with open(self._logfile, 'a') as opened_file: 405 | # Now we log to the specified logfile 406 | opened_file.write(log_string + '\n') 407 | # Now, send a notification 408 | self.notify() 409 | 410 |            # return base func 411 |            return self.func(*args) 412 | 413 |             414 | 415 | def notify(self): 416 | # logit only logs, no more 417 | pass 418 | 419 | This implementation has an additional advantage of being much cleaner than 420 | the nested function approach, and wrapping a function still will use 421 | the same syntax as before: 422 | 423 | .. code:: python 424 | 425 |    logit._logfile = 'out2.log' # if change log file 426 |    @logit 427 |    def myfunc1(): 428 | pass 429 | 430 | myfunc1() 431 | # Output: myfunc1 was called 432 | 433 | Now, let's subclass logit to add email functionality (though this topic 434 | will not be covered here). 435 | 436 | .. code:: python 437 | 438 | class email_logit(logit): 439 | ''' 440 | A logit implementation for sending emails to admins 441 | when the function is called. 442 | ''' 443 | def __init__(self, email='admin@myproject.com', *args, **kwargs): 444 | self.email = email 445 | super(email_logit, self).__init__(*args, **kwargs) 446 | 447 | def notify(self): 448 | # Send an email to self.email 449 | # Will not be implemented here 450 | pass 451 | 452 | From here, ``@email_logit`` works just like ``@logit`` but sends an email 453 | to the admin in addition to logging. 454 | -------------------------------------------------------------------------------- /enumerate.rst: -------------------------------------------------------------------------------- 1 | Enumerate 2 | --------- 3 | 4 | Enumerate is a built-in function of Python. Its usefulness can not be 5 | summarized in a single line. Yet most of the newcomers and even some 6 | advanced programmers are unaware of it. It allows us to loop over 7 | something and have an automatic counter. Here is an example: 8 | 9 | .. code:: python 10 | 11 | my_list = ['apple', 'banana', 'grapes', 'pear'] 12 | for counter, value in enumerate(my_list): 13 | print counter, value 14 | 15 | # Output: 16 | # 0 apple 17 | # 1 banana 18 | # 2 grapes 19 | # 3 pear 20 | 21 | And there is more! ``enumerate`` also accepts an optional argument that 22 | allows us to specify the starting index of the counter. 23 | 24 | .. code:: python 25 | 26 | my_list = ['apple', 'banana', 'grapes', 'pear'] 27 | for c, value in enumerate(my_list, 1): 28 | print(c, value) 29 | 30 | # Output: 31 | # 1 apple 32 | # 2 banana 33 | # 3 grapes 34 | # 4 pear 35 | 36 | An example of where the optional argument of ``enumerate`` comes in handy 37 | is creating tuples containing the index and list item using a list. Here 38 | is an example: 39 | 40 | .. code:: python 41 | 42 | my_list = ['apple', 'banana', 'grapes', 'pear'] 43 | counter_list = list(enumerate(my_list, 1)) 44 | print(counter_list) 45 | # Output: [(1, 'apple'), (2, 'banana'), (3, 'grapes'), (4, 'pear')] 46 | 47 | -------------------------------------------------------------------------------- /exceptions.rst: -------------------------------------------------------------------------------- 1 | Exceptions 2 | ---------- 3 | 4 | Exception handling is an art which once you master grants you immense 5 | powers. I am going to show you some of the ways in which we can handle 6 | exceptions. 7 | 8 | In basic terminology we are aware of the ``try/except`` structure. The code 9 | that can cause an exception to occur is put in the ``try`` block and 10 | the handling of the exception is implemented in the ``except`` block. 11 | The code in the ``except`` block will only execute if the ``try`` block 12 | runs into an exception. 13 | Here is a simple example: 14 | 15 | .. code:: python 16 | 17 | try: 18 | file = open('test.txt', 'rb') 19 | except IOError as e: 20 | print('An IOError occurred. {}'.format(e.args[-1])) 21 | 22 | In the above example we are handling only the IOError exception. What 23 | most beginners do not know is that we can handle multiple exceptions. 24 | 25 | Handling multiple exceptions: 26 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 27 | 28 | We can use three methods to handle multiple exceptions. The first one 29 | involves putting all the exceptions which are likely to occur in a 30 | tuple. Like so: 31 | 32 | .. code:: python 33 | 34 | try: 35 | file = open('test.txt', 'rb') 36 | except (IOError, EOFError) as e: 37 | print("An error occurred. {}".format(e.args[-1])) 38 | 39 | Another method is to handle individual exceptions in separate ``except`` 40 | blocks. We can have as many ``except`` blocks as we want. Here is an example: 41 | 42 | .. code:: python 43 | 44 | try: 45 | file = open('test.txt', 'rb') 46 | except EOFError as e: 47 | print("An EOF error occurred.") 48 | raise e 49 | except IOError as e: 50 | print("An error occurred.") 51 | raise e 52 | 53 | This way if the exception is not handled by the first ``except`` block then 54 | it may be handled by a following block, or none at all. Now the last method involves 55 | trapping ALL exceptions: 56 | 57 | .. code:: python 58 | 59 | try: 60 | file = open('test.txt', 'rb') 61 | except Exception as e: 62 | # Some logging if you want 63 | raise e 64 | 65 | This can be helpful when you have no idea about the exceptions that may 66 | be thrown by your program. If you are just looking to catch all execptions, 67 | but don't actually care about what they are, you can even exclude the 68 | ``Exception as e`` part. 69 | 70 | Note:: catching all exceptions may have unintended consequences because catching 71 | all exceptions may also catch the ones you want to occur; for example, in 72 | many command-line based programs, pressing control+c will terminate the program, 73 | but if you catch all excepts, the ``KeyboardInterrupt`` will be caught as an 74 | exception, so pressing control+c will NOT terminate the program. 75 | 76 | ``finally`` clause 77 | ~~~~~~~~~~~~~~~~~~ 78 | 79 | We wrap our main code in the ``try`` clause. After that we wrap some code in 80 | an ``except`` clause which gets executed if an exception occurs in the code 81 | wrapped in the ``try`` clause. In this example we will use a third clause as 82 | well which is the ``finally`` clause. The code which is wrapped in the 83 | ``finally`` clause will run whether or not an exception occurred. It might be used 84 | to perform clean-up after a script. Here is a simple example: 85 | 86 | .. code:: python 87 | 88 | try: 89 | file = open('test.txt', 'rb') 90 | except IOError as e: 91 | print('An IOError occurred. {}'.format(e.args[-1])) 92 | finally: 93 | print("This would be printed whether or not an exception occurred!") 94 | 95 | # Output: An IOError occurred. No such file or directory 96 | # This would be printed whether or not an exception occurred! 97 | 98 | ``try/else`` clause 99 | ~~~~~~~~~~~~~~~~~~~ 100 | 101 | Often times we might want some code to run if **no** exception occurs. This 102 | can easily be achieved by using an ``else`` clause. One might ask: why, if 103 | you only want some code to run if no exception occurs, wouldn't you simply 104 | put that code inside the ``try``? The answer is that then any exceptions in 105 | that code will be caught by the ``try``, and you might not want that. Most 106 | people don't use it and honestly I have myself not used it widely. Here is an 107 | example: 108 | 109 | .. code:: python 110 | 111 | try: 112 | print('I am sure no exception is going to occur!') 113 | except Exception: 114 | print('exception') 115 | else: 116 | # any code that should only run if no exception occurs in the try, 117 | # but for which exceptions should NOT be caught 118 | print('This would only run if no exception occurs. And an error here ' 119 | 'would NOT be caught.') 120 | finally: 121 | print('This would be printed in every case.') 122 | 123 | # Output: I am sure no exception is going to occur! 124 | # This would only run if no exception occurs. And an error here would NOT be caught 125 | # This would be printed in every case. 126 | 127 | The ``else`` clause would only run if no exception occurs and it would run 128 | before the ``finally`` clause. 129 | -------------------------------------------------------------------------------- /flaskstyle.sty: -------------------------------------------------------------------------------- 1 | \definecolor{TitleColor}{rgb}{0,0,0} 2 | \definecolor{InnerLinkColor}{rgb}{0,0,0} 3 | \usepackage{geometry} 4 | \usepackage{xcolor} 5 | \usepackage{pdfpages} 6 | \usepackage{graphicx} 7 | \usepackage{lipsum}% Used for dummy text. 8 | \definecolor{titlepagecolor}{cmyk}{1,.60,0,.40} 9 | \definecolor{namecolor}{cmyk}{1,.50,0,.10} 10 | \definecolor{VerbatimBorderColor}{rgb}{1,1,1} 11 | 12 | \renewcommand{\maketitle}{% 13 | 14 | \begin{titlepage} 15 | \includepdf[pages={1}]{cover.pdf} 16 | 17 | \end{titlepage} 18 | \restoregeometry % restores the geometry 19 | \nopagecolor% Use this to restore the color pages to white 20 | 21 | \cleardoublepage% 22 | \setcounter{footnote}{0}% 23 | \let\thanks\relax\let\maketitle\relax 24 | %\gdef\@thanks{}\gdef\@author{}\gdef\@title{} 25 | } 26 | 27 | \fancypagestyle{normal}{ 28 | \fancyhf{} 29 | \fancyfoot[LE,RO]{{\thepage}} 30 | \fancyfoot[LO]{{\nouppercase{\rightmark}}} 31 | \fancyfoot[RE]{{\nouppercase{\leftmark}}} 32 | \fancyhead[LE,RO]{{ \@title, \py@release}} 33 | \renewcommand{\headrulewidth}{0.4pt} 34 | \renewcommand{\footrulewidth}{0.4pt} 35 | } 36 | 37 | \fancypagestyle{plain}{ 38 | \fancyhf{} 39 | \fancyfoot[LE,RO]{{\thepage}} 40 | \renewcommand{\headrulewidth}{0pt} 41 | \renewcommand{\footrulewidth}{0.4pt} 42 | } 43 | 44 | \titleformat{\section}{\Large}% 45 | {\py@TitleColor\thesection}{0.5em}{\py@TitleColor}{\py@NormalColor} 46 | \titleformat{\subsection}{\large}% 47 | {\py@TitleColor\thesubsection}{0.5em}{\py@TitleColor}{\py@NormalColor} 48 | \titleformat{\subsubsection}{}% 49 | {\py@TitleColor\thesubsubsection}{0.5em}{\py@TitleColor}{\py@NormalColor} 50 | \titleformat{\paragraph}{\large}% 51 | {\py@TitleColor}{0em}{\py@TitleColor}{\py@NormalColor} 52 | 53 | \ChNameVar{\raggedleft\normalsize} 54 | \ChNumVar{\raggedleft \bfseries\Large} 55 | \ChTitleVar{\raggedleft \rm\Huge} 56 | 57 | \renewcommand\thepart{\@Roman\c@part} 58 | \renewcommand\part{% 59 | \pagestyle{plain} 60 | \if@noskipsec \leavevmode \fi 61 | \cleardoublepage 62 | \vspace*{6cm}% 63 | \@afterindentfalse 64 | \secdef\@part\@spart} 65 | 66 | \def\@part[#1]#2{% 67 | \ifnum \c@secnumdepth >\m@ne 68 | \refstepcounter{part}% 69 | \addcontentsline{toc}{part}{\thepart\hspace{1em}#1}% 70 | \else 71 | \addcontentsline{toc}{part}{#1}% 72 | \fi 73 | {\parindent \z@ %\center 74 | \interlinepenalty \@M 75 | \normalfont 76 | \ifnum \c@secnumdepth >\m@ne 77 | \rm\Large \partname~\thepart 78 | \par\nobreak 79 | \fi 80 | \MakeUppercase{\rm\Huge #2}% 81 | \markboth{}{}\par}% 82 | \nobreak 83 | \vskip 8ex 84 | \@afterheading} 85 | \def\@spart#1{% 86 | {\parindent \z@ %\center 87 | \interlinepenalty \@M 88 | \normalfont 89 | \huge \bfseries #1\par}% 90 | \nobreak 91 | \vskip 3ex 92 | \@afterheading} 93 | 94 | % use inconsolata font 95 | \usepackage{inconsolata} 96 | 97 | % fix single quotes, for inconsolata. (does not work) 98 | %%\usepackage{textcomp} 99 | %%\begingroup 100 | %% \catcode`'=\active 101 | %% \g@addto@macro\@noligs{\let'\textsinglequote} 102 | %% \endgroup 103 | %%\endinput 104 | -------------------------------------------------------------------------------- /for_-_else.rst: -------------------------------------------------------------------------------- 1 | ``for/else`` 2 | ------------ 3 | 4 | Loops are an integral part of any language. Likewise ``for`` loops are 5 | an important part of Python. However there are a few things which most 6 | beginners do not know about them. We will discuss a few of them one-by-one. 7 | 8 | Let's first start off with what we know. We know that we can use ``for`` loops 9 | like this: 10 | 11 | .. code:: python 12 | 13 | fruits = ['apple', 'banana', 'mango'] 14 | for fruit in fruits: 15 | print(fruit.capitalize()) 16 | 17 | # Output: Apple 18 | # Banana 19 | # Mango 20 | 21 | That is the very basic structure of a ``for`` loop. Now let's move on to 22 | some of the lesser known features of ``for`` loops in Python. 23 | 24 | ``else`` Clause 25 | ^^^^^^^^^^^^^^^ 26 | 27 | ``for`` loops also have an ``else`` clause which most of us are unfamiliar 28 | with. The ``else`` clause executes after the loop completes normally. 29 | This means that the loop did not encounter a ``break`` statement. They are 30 | really useful once you understand where to use them. I, myself, came to 31 | know about them a lot later. 32 | 33 | The common construct is to run a loop and search for an item. If the 34 | item is found, we break out of the loop using the ``break`` statement. There are two 35 | scenarios in which the loop may end. The first one is when the item is 36 | found and ``break`` is encountered. The second scenario is that the loop 37 | ends without encountering a ``break`` statement. Now we may want to know which one of these is the reason for a 38 | loop's completion. One method is to set a flag and then check it once the 39 | loop ends. Another is to use the ``else`` clause. 40 | 41 | This is the basic structure of a ``for/else`` loop: 42 | 43 | .. code:: python 44 | 45 | for item in container: 46 | if search_something(item): 47 | # Found it! 48 | process(item) 49 | break 50 | else: 51 | # Didn't find anything.. 52 | not_found_in_container() 53 | 54 | Consider this simple example which I took from the official 55 | documentation: 56 | 57 | .. code:: python 58 | 59 | for n in range(2, 10): 60 | for x in range(2, n): 61 | if n % x == 0: 62 | print(n, 'equals', x, '*', n/x) 63 | break 64 | 65 | It finds factors for numbers between 2 to 10. Now for the fun part. We 66 | can add an additional ``else`` block which catches the numbers which have no factors and are therefore prime numbers: 67 | 68 | .. code:: python 69 | 70 | for n in range(2, 10): 71 | for x in range(2, n): 72 | if n % x == 0: 73 | print( n, 'equals', x, '*', n/x) 74 | break 75 | else: 76 | # loop fell through without finding a factor 77 | print(n, 'is a prime number') 78 | -------------------------------------------------------------------------------- /function_caching.rst: -------------------------------------------------------------------------------- 1 | Function caching 2 | ---------------- 3 | 4 | Function caching allows us to cache the return values of a function 5 | depending on the arguments. It can save time when an I/O bound function 6 | is periodically called with the same arguments. Before Python 3.2 we had 7 | to write a custom implementation. In Python 3.2+ there is an 8 | ``lru_cache`` decorator which allows us to quickly cache and uncache the 9 | return values of a function. 10 | 11 | Let's see how we can use it in Python 3.2+ and the versions before it. 12 | 13 | Python 3.2+ 14 | ^^^^^^^^^^^ 15 | 16 | Let's implement a Fibonacci calculator and use ``lru_cache``. 17 | 18 | .. code:: python 19 | 20 | from functools import lru_cache 21 | 22 | @lru_cache(maxsize=32) 23 | def fib(n): 24 | if n < 2: 25 | return n 26 | return fib(n-1) + fib(n-2) 27 | 28 | >>> print([fib(n) for n in range(10)]) 29 | # Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] 30 | 31 | The ``maxsize`` argument tells ``lru_cache`` about how many recent 32 | return values to cache. 33 | 34 | We can easily uncache the return values as well by using: 35 | 36 | .. code:: python 37 | 38 | fib.cache_clear() 39 | 40 | Python 2+ 41 | ^^^^^^^^^ 42 | 43 | There are a couple of ways to achieve the same effect. You can create 44 | any type of caching mechanism. It entirely depends upon your needs. Here 45 | is a generic cache: 46 | 47 | .. code:: python 48 | 49 | from functools import wraps 50 | 51 | def memoize(function): 52 | memo = {} 53 | @wraps(function) 54 | def wrapper(*args): 55 | try: 56 | return memo[args] 57 | except KeyError: 58 | rv = function(*args) 59 | memo[args] = rv 60 | return rv 61 | return wrapper 62 | 63 | @memoize 64 | def fibonacci(n): 65 | if n < 2: return n 66 | return fibonacci(n - 1) + fibonacci(n - 2) 67 | 68 | fibonacci(25) 69 | 70 | **Note:** memoize won't cache unhashable types (dict, lists, etc...) but only the immutable types. Keep that in mind when using it. 71 | 72 | `Here `__ 73 | is a fine article by Caktus Group in which they caught a bug in Django 74 | which occurred due to ``lru_cache``. It's an interesting read. Do check it out. 75 | -------------------------------------------------------------------------------- /generators.rst: -------------------------------------------------------------------------------- 1 | Generators 2 | ---------- 3 | 4 | First lets understand iterators. According to Wikipedia, an iterator is 5 | an object that enables a programmer to traverse a container, 6 | particularly lists. However, an iterator performs traversal and gives 7 | access to data elements in a container, but does not perform iteration. 8 | You might be confused so lets take it a bit slow. There are three parts 9 | namely: 10 | 11 | - Iterable 12 | - Iterator 13 | - Iteration 14 | 15 | All of these parts are linked to each other. We will discuss them one by 16 | one and later talk about generators. 17 | 18 | Iterable 19 | ^^^^^^^^ 20 | 21 | An ``iterable`` is any object in Python which has an ``__iter__`` or a 22 | ``__getitem__`` method defined which returns an **iterator** or can take 23 | indexes (You can read more about them `here `_). 24 | In short an ``iterable`` is any object which can provide us 25 | with an **iterator**. So what is an **iterator**? 26 | 27 | Iterator 28 | ^^^^^^^^ 29 | 30 | An iterator is any object in Python which has a ``next`` (Python2) or 31 | ``__next__`` method defined. That's it. That's an iterator. Now let's 32 | understand **iteration**. 33 | 34 | Iteration 35 | ^^^^^^^^^ 36 | 37 | In simple words it is the process of taking an item from something e.g a 38 | list. When we use a loop to loop over something it is called iteration. 39 | It is the name given to the process itself. Now as we have a basic 40 | understanding of these terms let's understand **generators**. 41 | 42 | Generators 43 | ^^^^^^^^^^ 44 | 45 | Generators are iterators, but you can only iterate over them once. It’s 46 | because they do not store all the values in memory, they generate the 47 | values on the fly. You use them by iterating over them, either with a 48 | 'for' loop or by passing them to any function or construct that 49 | iterates. Most of the time ``generators`` are implemented as functions. 50 | However, they do not ``return`` a value, they ``yield`` it. Here is a 51 | simple example of a ``generator`` function: 52 | 53 | .. code:: python 54 | 55 | def generator_function(): 56 | for i in range(10): 57 | yield i 58 | 59 | for item in generator_function(): 60 | print(item) 61 | 62 | # Output: 0 63 | # 1 64 | # 2 65 | # 3 66 | # 4 67 | # 5 68 | # 6 69 | # 7 70 | # 8 71 | # 9 72 | 73 | It is not really useful in this case. Generators are best for 74 | calculating large sets of results (particularly calculations involving 75 | loops themselves) where you don't want to allocate the memory for all 76 | results at the same time. Many Standard Library functions that return 77 | ``lists`` in Python 2 have been modified to return ``generators`` in 78 | Python 3 because ``generators`` require fewer resources. 79 | 80 | Here is an example ``generator`` which calculates fibonacci numbers: 81 | 82 | .. code:: python 83 | 84 | # generator version 85 | def fibon(n): 86 | a = b = 1 87 | for i in range(n): 88 | yield a 89 | a, b = b, a + b 90 | 91 | Now we can use it like this: 92 | 93 | .. code:: python 94 | 95 | for x in fibon(1000000): 96 | print(x) 97 | 98 | This way we would not have to worry about it using a lot of resources. 99 | However, if we would have implemented it like this: 100 | 101 | .. code:: python 102 | 103 | def fibon(n): 104 | a = b = 1 105 | result = [] 106 | for i in range(n): 107 | result.append(a) 108 | a, b = b, a + b 109 | return result 110 | 111 | It would have used up all our resources while calculating a large input. 112 | We have discussed that we can iterate over ``generators`` only once but 113 | we haven't tested it. Before testing it you need to know about one more 114 | built-in function of Python, ``next()``. It allows us to access the next 115 | element of a sequence. So let's test out our understanding: 116 | 117 | .. code:: python 118 | 119 | def generator_function(): 120 | for i in range(3): 121 | yield i 122 | 123 | gen = generator_function() 124 | print(next(gen)) 125 | # Output: 0 126 | print(next(gen)) 127 | # Output: 1 128 | print(next(gen)) 129 | # Output: 2 130 | print(next(gen)) 131 | # Output: Traceback (most recent call last): 132 | # File "", line 1, in 133 | # StopIteration 134 | 135 | As we can see that after yielding all the values ``next()`` caused a 136 | ``StopIteration`` error. Basically this error informs us that all the 137 | values have been yielded. You might be wondering why we don't get 138 | this error when using a ``for`` loop? Well the answer is simple. The 139 | ``for`` loop automatically catches this error and stops calling 140 | ``next``. Did you know that a few built-in data types in Python also 141 | support iteration? Let's check it out: 142 | 143 | .. code:: python 144 | 145 | my_string = "Yasoob" 146 | next(my_string) 147 | # Output: Traceback (most recent call last): 148 | # File "", line 1, in 149 | # TypeError: str object is not an iterator 150 | 151 | Well that's not what we expected. The error says that ``str`` is not an 152 | iterator. Well it's right! It's an iterable but not an iterator. This 153 | means that it supports iteration but we can't iterate over 154 | it directly. So how would we iterate over it? It's time to learn about one more 155 | built-in function, ``iter``. It returns an ``iterator`` object from an 156 | iterable. While an ``int`` isn't an iterable, we can use it on string! 157 | 158 | .. code:: python 159 | 160 | int_var = 1779 161 | iter(int_var) 162 | # Output: Traceback (most recent call last): 163 | # File "", line 1, in 164 | # TypeError: 'int' object is not iterable 165 | # This is because int is not iterable 166 | 167 | my_string = "Yasoob" 168 | my_iter = iter(my_string) 169 | print(next(my_iter)) 170 | # Output: 'Y' 171 | 172 | Now that is much better. I am sure that you loved learning about 173 | generators. Do bear it in mind that you can fully grasp this concept 174 | only when you use it. Make sure that you follow this pattern and use 175 | ``generators`` whenever they make sense to you. You won't be 176 | disappointed! 177 | -------------------------------------------------------------------------------- /global_&_return.rst: -------------------------------------------------------------------------------- 1 | Global and Return 2 | --------------- 3 | 4 | You might have encountered some functions written in Python which have a 5 | ``return`` keyword in the end of the function. Do you know what it does? It 6 | is similar to return in other languages. Let's examine this little 7 | function: 8 | 9 | .. code:: python 10 | 11 | def add(value1, value2): 12 | return value1 + value2 13 | 14 | result = add(3, 5) 15 | print(result) 16 | # Output: 8 17 | 18 | The function above takes two values as input and then outputs their 19 | addition. We could have also done: 20 | 21 | .. code:: python 22 | 23 | def add(value1,value2): 24 | global result 25 | result = value1 + value2 26 | 27 | add(3,5) 28 | print(result) 29 | # Output: 8 30 | 31 | So first let's talk about the first bit of code which involves the 32 | ``return`` keyword. What that function is doing is that it is assigning 33 | the value to the variable which is calling that function which in our 34 | case is ``result``. In most cases you won't need to use the 35 | ``global`` keyword. However, let's examine the other bit of code as well 36 | which includes the ``global`` keyword. So what that function is doing is 37 | that it is making a global variable ``result``. What does global mean 38 | here? Global variable means that we can access that variable outside the 39 | scope of the function as well. Let me demonstrate it with an example: 40 | 41 | .. code:: python 42 | 43 | # first without the global variable 44 | def add(value1, value2): 45 | result = value1 + value2 46 | 47 | add(2, 4) 48 | print(result) 49 | 50 | # Oh crap, we encountered an exception. Why is it so? 51 | # the python interpreter is telling us that we do not 52 | # have any variable with the name of result. It is so 53 | # because the result variable is only accessible inside 54 | # the function in which it is created if it is not global. 55 | Traceback (most recent call last): 56 | File "", line 1, in 57 | result 58 | NameError: name 'result' is not defined 59 | 60 | # Now lets run the same code but after making the result 61 | # variable global 62 | def add(value1, value2): 63 | global result 64 | result = value1 + value2 65 | 66 | add(2, 4) 67 | result 68 | 6 69 | 70 | So hopefully there are no errors in the second run as expected. In 71 | practical programming you should try to stay away from ``global`` 72 | keyword as it only makes life difficult by introducing unwanted variables 73 | to the global scope. 74 | 75 | Multiple return values 76 | ^^^^^^^^^^^^^^^^^^^^^^^ 77 | 78 | So what if you want to return two variables from a function instead of one? There are a couple of approaches which new programmers take. The most famous approach is to use ``global`` keyword. Let's take a look at a useless example: 79 | 80 | .. code:: python 81 | 82 | def profile(): 83 | global name 84 | global age 85 | name = "Danny" 86 | age = 30 87 | 88 | profile() 89 | print(name) 90 | # Output: Danny 91 | 92 | print(age) 93 | # Output: 30 94 | 95 | **Note:**Don't try to use the above mentioned method. I repeat, don't try to use the above mentioned method! 96 | 97 | Some try to solve this problem by *returning* a ``tuple``, ``list`` or ``dict`` with the required values after the function terminates. It is one way to do it and works like a charm: 98 | 99 | .. code:: python 100 | 101 | def profile(): 102 | name = "Danny" 103 | age = 30 104 | return (name, age) 105 | 106 | profile_data = profile() 107 | print(profile_data[0]) 108 | # Output: Danny 109 | 110 | print(profile_data[1]) 111 | # Output: 30 112 | 113 | Or by more common convention: 114 | 115 | .. code:: python 116 | 117 | def profile(): 118 | name = "Danny" 119 | age = 30 120 | return name, age 121 | 122 | profile_name, profile_age = profile() 123 | print(profile_name) 124 | # Output: Danny 125 | print(profile_age) 126 | # Output: 30 127 | 128 | Keep in mind that even in the above example we are returning a tuple (despite the lack of parenthesis) and not separate multiple values. If you want to take it one step further, you can also make use of `namedtuple `_. Here is an example: 129 | 130 | .. code:: python 131 | 132 | from collections import namedtuple 133 | def profile(): 134 | Person = namedtuple('Person', 'name age') 135 | return Person(name="Danny", age=31) 136 | 137 | # Use as namedtuple 138 | p = profile() 139 | print(p, type(p)) 140 | # Person(name='Danny', age=31) 141 | print(p.name) 142 | # Danny 143 | print(p.age) 144 | #31 145 | 146 | # Use as plain tuple 147 | p = profile() 148 | print(p[0]) 149 | # Danny 150 | print(p[1]) 151 | #31 152 | 153 | # Unpack it immediatly 154 | name, age = profile() 155 | print(name) 156 | # Danny 157 | print(age) 158 | #31 159 | 160 | This is a better way to do it, along with returning ``list`` and ``dict``. Don't use ``global`` keyword unless you know what you are doing. ``global`` might be a better option in a few cases but is not in most of them. 161 | -------------------------------------------------------------------------------- /index.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | .. note:: 4 | 5 | You can sign up to my `mailing list `__ so that you remain in sync with any major updates to this book or my future projects! 6 | 7 | Intermediate Python 8 | =================== 9 | 10 | ============ 11 | Preface 12 | ============ 13 | 14 | Python is an amazing language with a strong and friendly community of programmers. However, there is a lack of documentation on what to learn after getting the basics of Python down your throat. Through this book I aim to solve this problem. I would give you bits of information about some interesting topics which you can further explore. 15 | 16 | The topics which are discussed in this book open up your mind towards some nice corners of Python language. This book is an outcome of my desire to have something like this when I was beginning to learn Python. 17 | 18 | If you are a beginner, intermediate or even an advanced programmer there is something for you in this book. 19 | 20 | Please note that this book is not a tutorial and does not teach you Python. The topics are not explained in depth, instead only the minimum required information is given. 21 | 22 | I am sure you are as excited as I am so let’s start! 23 | 24 | **Note:** This book is a continuous work in progress. If you find anything which you can further improve (I know you will find a lot of stuff) then kindly submit a pull request! 25 | 26 | ================== 27 | Author 28 | ================== 29 | 30 | I am Muhammad Yasoob Ullah Khalid. I have been programming extensively in Python for over 3 years now. I have been involved in a lot of Open Source projects. I regularly blog about interesting Python topics over at my `blog `_ . In 2014 I also spoke at EuroPython which was held in Berlin. It is the biggest Python conference in Europe. If you have an interesting Internship opportunity for me then I would definitely like to hear from you! 31 | 32 | ================== 33 | Table of Contents 34 | ================== 35 | 36 | .. toctree:: 37 | :maxdepth: 2 38 | :numbered: 39 | 40 | args_and_kwargs 41 | debugging 42 | generators 43 | map_filter 44 | set_-_data_structure 45 | ternary_operators 46 | decorators 47 | global_&_return 48 | mutation 49 | __slots__magic 50 | virtual_environment 51 | collections 52 | enumerate 53 | zip 54 | object_introspection 55 | comprehensions 56 | exceptions 57 | classes 58 | lambdas 59 | one_liners 60 | for_-_else 61 | python_c_extension 62 | open_function 63 | targeting_python_2_3 64 | coroutines 65 | function_caching 66 | context_managers 67 | -------------------------------------------------------------------------------- /lambdas.rst: -------------------------------------------------------------------------------- 1 | Lambdas 2 | ------- 3 | 4 | Lambdas are one line functions. They are also known as anonymous 5 | functions in some other languages. You might want to use lambdas when 6 | you don't want to use a function twice in a program. They are just like 7 | normal functions and even behave like them. 8 | 9 | **Blueprint** 10 | 11 | .. code:: python 12 | 13 | lambda argument: manipulate(argument) 14 | 15 | **Example** 16 | 17 | .. code:: python 18 | 19 | add = lambda x, y: x + y 20 | 21 | print(add(3, 5)) 22 | # Output: 8 23 | 24 | Here are a few useful use cases for lambdas and just a few ways in which 25 | they are used in the wild: 26 | 27 | **List sorting** 28 | 29 | .. code:: python 30 | 31 | a = [(1, 2), (4, 1), (9, 10), (13, -3)] 32 | a.sort(key=lambda x: x[1]) 33 | 34 | print(a) 35 | # Output: [(13, -3), (4, 1), (1, 2), (9, 10)] 36 | 37 | **Parallel sorting of lists** 38 | 39 | .. code:: python 40 | 41 | data = zip(list1, list2) 42 | data = sorted(data) 43 | list1, list2 = map(lambda t: list(t), zip(*data)) 44 | -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | goto end 41 | ) 42 | 43 | if "%1" == "clean" ( 44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 45 | del /q /s %BUILDDIR%\* 46 | goto end 47 | ) 48 | 49 | 50 | %SPHINXBUILD% 2> nul 51 | if errorlevel 9009 ( 52 | echo. 53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 54 | echo.installed, then set the SPHINXBUILD environment variable to point 55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 56 | echo.may add the Sphinx directory to PATH. 57 | echo. 58 | echo.If you don't have Sphinx installed, grab it from 59 | echo.http://sphinx-doc.org/ 60 | exit /b 1 61 | ) 62 | 63 | if "%1" == "html" ( 64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 68 | goto end 69 | ) 70 | 71 | if "%1" == "dirhtml" ( 72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 76 | goto end 77 | ) 78 | 79 | if "%1" == "singlehtml" ( 80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 84 | goto end 85 | ) 86 | 87 | if "%1" == "pickle" ( 88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can process the pickle files. 92 | goto end 93 | ) 94 | 95 | if "%1" == "json" ( 96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished; now you can process the JSON files. 100 | goto end 101 | ) 102 | 103 | if "%1" == "htmlhelp" ( 104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can run HTML Help Workshop with the ^ 108 | .hhp project file in %BUILDDIR%/htmlhelp. 109 | goto end 110 | ) 111 | 112 | if "%1" == "qthelp" ( 113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 117 | .qhcp project file in %BUILDDIR%/qthelp, like this: 118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\PythonTips.qhcp 119 | echo.To view the help file: 120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\PythonTips.ghc 121 | goto end 122 | ) 123 | 124 | if "%1" == "devhelp" ( 125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished. 129 | goto end 130 | ) 131 | 132 | if "%1" == "epub" ( 133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 137 | goto end 138 | ) 139 | 140 | if "%1" == "latex" ( 141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 145 | goto end 146 | ) 147 | 148 | if "%1" == "latexpdf" ( 149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 150 | cd %BUILDDIR%/latex 151 | make all-pdf 152 | cd %BUILDDIR%/.. 153 | echo. 154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 155 | goto end 156 | ) 157 | 158 | if "%1" == "latexpdfja" ( 159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 160 | cd %BUILDDIR%/latex 161 | make all-pdf-ja 162 | cd %BUILDDIR%/.. 163 | echo. 164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 165 | goto end 166 | ) 167 | 168 | if "%1" == "text" ( 169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.Build finished. The text files are in %BUILDDIR%/text. 173 | goto end 174 | ) 175 | 176 | if "%1" == "man" ( 177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 181 | goto end 182 | ) 183 | 184 | if "%1" == "texinfo" ( 185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 186 | if errorlevel 1 exit /b 1 187 | echo. 188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 189 | goto end 190 | ) 191 | 192 | if "%1" == "gettext" ( 193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 197 | goto end 198 | ) 199 | 200 | if "%1" == "changes" ( 201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.The overview file is in %BUILDDIR%/changes. 205 | goto end 206 | ) 207 | 208 | if "%1" == "linkcheck" ( 209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Link check complete; look for any errors in the above output ^ 213 | or in %BUILDDIR%/linkcheck/output.txt. 214 | goto end 215 | ) 216 | 217 | if "%1" == "doctest" ( 218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 219 | if errorlevel 1 exit /b 1 220 | echo. 221 | echo.Testing of doctests in the sources finished, look at the ^ 222 | results in %BUILDDIR%/doctest/output.txt. 223 | goto end 224 | ) 225 | 226 | if "%1" == "xml" ( 227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 228 | if errorlevel 1 exit /b 1 229 | echo. 230 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 231 | goto end 232 | ) 233 | 234 | if "%1" == "pseudoxml" ( 235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 236 | if errorlevel 1 exit /b 1 237 | echo. 238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 239 | goto end 240 | ) 241 | 242 | :end 243 | -------------------------------------------------------------------------------- /map_filter.rst: -------------------------------------------------------------------------------- 1 | Map, Filter and Reduce 2 | ------------ 3 | 4 | These are three functions which facilitate a functional approach to 5 | programming. We will discuss them one by one and understand their use 6 | cases. 7 | 8 | Map 9 | ^^^^^^ 10 | 11 | ``Map`` applies a function to all the items in an input\_list. Here is 12 | the blueprint: 13 | 14 | **Blueprint** 15 | 16 | .. code:: python 17 | 18 | map(function_to_apply, list_of_inputs) 19 | 20 | Most of the times we want to pass all the list elements to a function 21 | one-by-one and then collect the output. For instance: 22 | 23 | .. code:: python 24 | 25 | items = [1, 2, 3, 4, 5] 26 | squared = [] 27 | for i in items: 28 | squared.append(i**2) 29 | 30 | ``Map`` allows us to implement this in a much simpler and nicer way. 31 | Here you go: 32 | 33 | .. code:: python 34 | 35 | items = [1, 2, 3, 4, 5] 36 | squared = list(map(lambda x: x**2, items)) 37 | 38 | Most of the times we use lambdas with ``map`` so I did the same. Instead 39 | of a list of inputs we can even have a list of functions! 40 | 41 | .. code:: python 42 | 43 | def multiply(x): 44 | return (x*x) 45 | def add(x): 46 | return (x+x) 47 | 48 | funcs = [multiply, add] 49 | for i in range(5): 50 | value = list(map(lambda x: x(i), funcs)) 51 | print(value) 52 | 53 | # Output: 54 | # [0, 0] 55 | # [1, 2] 56 | # [4, 4] 57 | # [9, 6] 58 | # [16, 8] 59 | 60 | Filter 61 | ^^^^^^^^^ 62 | 63 | As the name suggests, ``filter`` creates a list of elements for which a 64 | function returns true. Here is a short and concise example: 65 | 66 | .. code:: python 67 | 68 | number_list = range(-5, 5) 69 | less_than_zero = list(filter(lambda x: x < 0, number_list)) 70 | print(less_than_zero) 71 | 72 | # Output: [-5, -4, -3, -2, -1] 73 | 74 | The filter resembles a for loop but it is a builtin function and faster. 75 | 76 | **Note:** If map & filter do not appear beautiful to you then you can 77 | read about ``list/dict/tuple`` comprehensions. 78 | 79 | Reduce 80 | ^^^^^^^^^ 81 | 82 | ``Reduce`` is a really useful function for performing some computation on 83 | a list and returning the result. It applies a rolling computation to sequential 84 | pairs of values in a list. For example, if you wanted to compute the product 85 | of a list of integers. 86 | 87 | So the normal way you might go about doing this task in python is using 88 | a basic for loop: 89 | 90 | .. code:: python 91 | 92 | product = 1 93 | list = [1, 2, 3, 4] 94 | for num in list: 95 | product = product * num 96 | 97 | # product = 24 98 | 99 | 100 | Now let's try it with reduce: 101 | 102 | .. code:: python 103 | 104 | from functools import reduce 105 | product = reduce((lambda x, y: x * y), [1, 2, 3, 4]) 106 | 107 | # Output: 24 108 | -------------------------------------------------------------------------------- /mutation.rst: -------------------------------------------------------------------------------- 1 | Mutation 2 | -------- 3 | 4 | The mutable and immutable datatypes in Python cause a lot of headache 5 | for new programmers. In simple words, mutable means 'able to be changed' 6 | and immutable means 'constant'. Want your head to spin? Consider this 7 | example: 8 | 9 | .. code:: python 10 | 11 | foo = ['hi'] 12 | print(foo) 13 | # Output: ['hi'] 14 | 15 | bar = foo 16 | bar += ['bye'] 17 | print(foo) 18 | # Output: ['hi', 'bye'] 19 | 20 | What just happened? We were not expecting that! We were expecting 21 | something like this: 22 | 23 | .. code:: python 24 | 25 | foo = ['hi'] 26 | print(foo) 27 | # Output: ['hi'] 28 | 29 | bar = foo 30 | bar += ['bye'] 31 | 32 | print(foo) 33 | # Expected Output: ['hi'] 34 | # Output: ['hi', 'bye'] 35 | 36 | print(bar) 37 | # Output: ['hi', 'bye'] 38 | 39 | It's not a bug. It's mutability in action. Whenever you assign a 40 | variable to another variable of mutable datatype, any changes to the 41 | data are reflected by both variables. The new variable is just an alias 42 | for the old variable. This is only true for mutable datatypes. Here is a 43 | gotcha involving functions and mutable data types: 44 | 45 | .. code:: python 46 | 47 | def add_to(num, target=[]): 48 | target.append(num) 49 | return target 50 | 51 | add_to(1) 52 | # Output: [1] 53 | 54 | add_to(2) 55 | # Output: [1, 2] 56 | 57 | add_to(3) 58 | # Output: [1, 2, 3] 59 | 60 | You might have expected it to behave differently. You might be expecting 61 | that a fresh list would be created when you call ``add_to`` like this: 62 | 63 | .. code:: python 64 | 65 | def add_to(num, target=[]): 66 | target.append(num) 67 | return target 68 | 69 | add_to(1) 70 | # Output: [1] 71 | 72 | add_to(2) 73 | # Output: [2] 74 | 75 | add_to(3) 76 | # Output: [3] 77 | 78 | Well again it is the mutability of lists which causes this pain. In 79 | Python the default arguments are evaluated once when the function is 80 | defined, not each time the function is called. You should never define 81 | default arguments of mutable type unless you know what you are doing. 82 | You should do something like this: 83 | 84 | .. code:: python 85 | 86 | def add_to(element, target=None): 87 | if target is None: 88 | target = [] 89 | target.append(element) 90 | return target 91 | 92 | Now whenever you call the function without the ``target`` argument, a 93 | new list is created. For instance: 94 | 95 | .. code:: python 96 | 97 | add_to(42) 98 | # Output: [42] 99 | 100 | add_to(42) 101 | # Output: [42] 102 | 103 | add_to(42) 104 | # Output: [42] 105 | 106 | -------------------------------------------------------------------------------- /object_introspection.rst: -------------------------------------------------------------------------------- 1 | Object introspection 2 | -------------------- 3 | 4 | In computer programming, introspection is the ability to determine the 5 | type of an object at runtime. It is one of Python's strengths. 6 | Everything in Python is an object and we can examine those objects. 7 | Python ships with a few built-in functions and modules to help us. 8 | 9 | ``dir`` 10 | ^^^^^^^^^^^ 11 | 12 | In this section we will learn about ``dir`` and how it facilitates us 13 | in introspection. 14 | 15 | It is one of the most important functions for introspection. It returns 16 | a list of attributes and methods belonging to an object. Here is an 17 | example: 18 | 19 | .. code:: python 20 | 21 | my_list = [1, 2, 3] 22 | dir(my_list) 23 | # Output: ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', 24 | # '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', 25 | # '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', 26 | # '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', 27 | # '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', 28 | # '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', 29 | # '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 30 | # 'remove', 'reverse', 'sort'] 31 | 32 | Our introspection gave us the names of all the methods of a list. This 33 | can be handy when you are not able to recall a method name. If we run 34 | ``dir()`` without any argument then it returns all names in the current 35 | scope. 36 | 37 | ``type`` and ``id`` 38 | ^^^^^^^^^^^^^^^^^^^^^^^ 39 | 40 | The ``type`` function returns the type of an object. For example: 41 | 42 | .. code:: python 43 | 44 | print(type('')) 45 | # Output: 46 | 47 | print(type([])) 48 | # Output: 49 | 50 | print(type({})) 51 | # Output: 52 | 53 | print(type(dict)) 54 | # Output: 55 | 56 | print(type(3)) 57 | # Output: 58 | 59 | ``id`` returns the unique ids of various objects. For instance: 60 | 61 | .. code:: python 62 | 63 | name = "Yasoob" 64 | print(id(name)) 65 | # Output: 139972439030304 66 | 67 | ``inspect`` module 68 | ^^^^^^^^^^^^^^^^^^^^^^ 69 | 70 | The inspect module also provides several useful functions to get 71 | information about live objects. For example you can check the members of 72 | an object by running: 73 | 74 | .. code:: python 75 | 76 | import inspect 77 | print(inspect.getmembers(str)) 78 | # Output: [('__add__', `__. 143 | -------------------------------------------------------------------------------- /open_function.rst: -------------------------------------------------------------------------------- 1 | ``open`` Function 2 | ------------- 3 | 4 | `open `__ opens 5 | a file. Pretty simple, eh? Most of the time, we see it being used like 6 | this: 7 | 8 | .. code:: python 9 | 10 | f = open('photo.jpg', 'r+') 11 | jpgdata = f.read() 12 | f.close() 13 | 14 | The reason I am writing this article is that most of the time, I see 15 | open used like this. There are **three** errors in the above code. Can 16 | you spot them all? If not, read on. By the end of this article, you'll 17 | know what's wrong in the above code, and, more importantly, be able to 18 | avoid these mistakes in your own code. Let's start with the basics: 19 | 20 | The return value from ``open`` is a file handle, given out from the operating system 21 | to your Python application. You will want to return this file handle 22 | once you're finished with the file, if only so that your application 23 | won't reach the limit of the number of open file handles it can have at 24 | once. 25 | 26 | Explicitly calling ``close`` closes the file handle, but only if the 27 | read was successful. If there is any error just after ``f = open(...)``, 28 | ``f.close()`` will not be called (depending on the Python interpreter, 29 | the file handle may still be returned, but that's another story). To 30 | make sure that the file gets closed whether an exception occurs or not, 31 | pack it into a ``with`` statement: 32 | 33 | .. code:: python 34 | 35 | with open('photo.jpg', 'r+') as f: 36 | jpgdata = f.read() 37 | 38 | The first argument of ``open`` is the filename. The second one (the 39 | *mode*) determines *how* the file gets opened. 40 | 41 | - If you want to read the file, pass in ``r`` 42 | - If you want to read and write the file, pass in ``r+`` 43 | - If you want to overwrite the file, pass in ``w`` 44 | - If you want to append to the file, pass in ``a`` 45 | 46 | While there are a couple of other valid mode strings, chances are you 47 | won't ever use them. The mode matters not only because it changes the 48 | behavior, but also because it may result in permission errors. For 49 | example, if we were to open a jpg-file in a write-protected directory, 50 | ``open(.., 'r+')`` would fail. The mode can contain one further 51 | character; we can open the file in binary (you'll get a string of bytes) 52 | or text mode (a string of characters). 53 | 54 | In general, if the format is written by humans, it tends to be text 55 | mode. ``jpg`` image files are not generally written by humans (and are 56 | indeed not readable by humans), and you should therefore open them in 57 | binary mode by adding a ``b`` to the mode string (if you're following 58 | the opening example, the correct mode would be ``rb``). If you open 59 | something in text mode (i.e. add a ``t``, or nothing apart from 60 | ``r/r+/w/a``), you must also know which encoding to use. For a 61 | computer, all files are just bytes, not characters. 62 | 63 | Unfortunately, ``open`` does not allow explicit encoding specification 64 | in Python 2.x. However, the function 65 | `io.open `__ is 66 | available in both Python 2.x and 3.x (where it is an alias of ``open``), 67 | and does the right thing. You can pass in the encoding with the 68 | ``encoding`` keyword. If you don't pass in any encoding, a system -- and 69 | Python -- specific default will be picked. You may be tempted to rely on 70 | these defaults, but the defaults are often wrong, or the default 71 | encoding cannot actually express all characters in the file (this will happen often on 72 | Python 2.x and/or Windows). So go ahead and pick an encoding. Encoding is the way to instruct computers about how the numbers should be stored as bytes in memory. ``utf-8`` 73 | is a terrific one and is supported by major browsers and programming languages. When you write a file, you can just pick the encoding 74 | to your liking (or the liking of the program that will eventually read 75 | your file). 76 | 77 | How do you find out which encoding a file you're reading was written in? Well, 78 | unfortunately, there is no foolproof way to detect the encoding - the 79 | same bytes can represent different, but equally valid characters in 80 | different encodings. Therefore, you must rely on metadata (for example, 81 | in HTTP headers) to know the encoding. Increasingly, formats just define 82 | the encoding to be UTF-8. 83 | 84 | Armed with this knowledge, let's write a program that reads a file, 85 | determines whether it's JPG (hint: These files start with the bytes 86 | ``FF D8``), and writes a text file that describe the input file. 87 | 88 | .. code:: python 89 | 90 | import io 91 | 92 | with open('photo.jpg', 'rb') as inf: 93 | jpgdata = inf.read() 94 | 95 | if jpgdata.startswith(b'\xff\xd8'): 96 | text = u'This is a JPEG file (%d bytes long)\n' 97 | else: 98 | text = u'This is a random file (%d bytes long)\n' 99 | 100 | with io.open('summary.txt', 'w', encoding='utf-8') as outf: 101 | outf.write(text % len(jpgdata)) 102 | 103 | I am sure that now you will use ``open`` correctly! 104 | -------------------------------------------------------------------------------- /params.json: -------------------------------------------------------------------------------- 1 | {"name":"Python-book","tagline":"Intermediate Python","body":"### Welcome to GitHub Pages.\r\nThis automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here [using GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/), select a template crafted by a designer, and publish. After your page is generated, you can check out the new `gh-pages` branch locally. If you’re using GitHub Desktop, simply sync your repository and you’ll see the new branch.\r\n\r\n### Designer Templates\r\nWe’ve crafted some handsome templates for you to use. Go ahead and click 'Continue to layouts' to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved.\r\n\r\n### Creating pages manually\r\nIf you prefer to not use the automatic generator, push a branch named `gh-pages` to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.\r\n\r\n### Authors and Contributors\r\nYou can @mention a GitHub username to generate a link to their profile. The resulting `` element will link to the contributor’s GitHub Profile. For example: In 2007, Chris Wanstrath (@defunkt), PJ Hyett (@pjhyett), and Tom Preston-Werner (@mojombo) founded GitHub.\r\n\r\n### Support or Contact\r\nHaving trouble with Pages? Check out our [documentation](https://help.github.com/pages) or [contact support](https://github.com/contact) and we’ll help you sort it out.\r\n","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."} -------------------------------------------------------------------------------- /python_c_extension.rst: -------------------------------------------------------------------------------- 1 | Python C extensions 2 | =================== 3 | 4 | An interesting feature offered to developers by the CPython 5 | implementation is the ease of interfacing C code to Python. 6 | 7 | There are three key methods developers use to call C functions from 8 | their python code - ``ctypes``, ``SWIG`` and ``Python/C API``. Each 9 | method comes with its own merits and demerits. 10 | 11 | Firstly, why would you want to interface C with Python? 12 | 13 | A few common reasons are : 14 | 15 | - You want speed and you know C is about 50x faster than Python. 16 | - Certain legacy C libraries work just as well as you want them to, so you don't want to rewrite them in python. 17 | - Certain low level resource access - from memory to file interfaces. 18 | - Just because you want to. 19 | 20 | CTypes 21 | --------- 22 | 23 | The Python `ctypes 24 | module `__ is probably 25 | the easiest way to call C functions from Python. The ctypes module 26 | provides C compatible data types and functions to load DLLs so that 27 | calls can be made to C shared libraries without having to modify them. 28 | The fact that the C side needn't be touched adds to the simplicity of 29 | this method. 30 | 31 | **Example** 32 | 33 | Simple C code to add two numbers, save it as ``add.c`` 34 | 35 | .. code:: c 36 | 37 | //sample C file to add 2 numbers - int and floats 38 | 39 | int add_int(int, int); 40 | float add_float(float, float); 41 | 42 | int add_int(int num1, int num2){ 43 | return num1 + num2; 44 | } 45 | 46 | float add_float(float num1, float num2){ 47 | return num1 + num2; 48 | } 49 | 50 | Next compile the C file to a ``.so`` file (DLL in windows) This will 51 | generate an adder.so file. 52 | 53 | .. code:: bash 54 | 55 | #For Linux 56 | $ gcc -shared -Wl,-soname,adder -o adder.so -fPIC add.c 57 | 58 | #For Mac 59 | $ gcc -shared -Wl,-install_name,adder.so -o adder.so -fPIC add.c 60 | 61 | Now in your python code - 62 | 63 | .. code:: python 64 | 65 | from ctypes import * 66 | 67 | #load the shared object file 68 | adder = CDLL('./adder.so') 69 | 70 | #Find sum of integers 71 | res_int = adder.add_int(4,5) 72 | print "Sum of 4 and 5 = " + str(res_int) 73 | 74 | #Find sum of floats 75 | a = c_float(5.5) 76 | b = c_float(4.1) 77 | 78 | add_float = adder.add_float 79 | add_float.restype = c_float 80 | print "Sum of 5.5 and 4.1 = ", str(add_float(a, b)) 81 | 82 | And the output is as follows 83 | 84 | :: 85 | 86 | Sum of 4 and 5 = 9 87 | Sum of 5.5 and 4.1 = 9.60000038147 88 | 89 | In this example the C file is self explanatory - it contains two 90 | functions, one to add two integers and another to add two floats. 91 | 92 | In the python file, first the ctypes module is imported. Then the CDLL 93 | function of the ctypes module is used to load the shared lib file we 94 | created. The functions defined in the C lib are now available to us via 95 | the ``adder`` variable. When ``adder.add_int()`` is called, internally a 96 | call is made to the ``add_int`` C function. The ctypes interface allows 97 | us to use native python integers and strings by default while calling 98 | the C functions. 99 | 100 | For other types such as boolean or float, we have to use the correct 101 | ctypes. This is seen while passing parameters to the 102 | ``adder.add_float()``. We first create the required c\_float types from 103 | python decimal values, and then use them as arguments to the C code. 104 | This method is simple and clean, but limited. For example it's not 105 | possible to manipulate objects on the C side. 106 | 107 | SWIG 108 | ------- 109 | 110 | Simplified Wrapper and Interface Generator, or SWIG for short is another 111 | way to interface C code to Python. In this method, the developer must 112 | develop an extra interface file which is an input to SWIG (the command 113 | line utility). 114 | 115 | Python developers generally don't use this method, because it is in most 116 | cases unnecessarily complex. This is a great method when you have a 117 | C/C++ code base, and you want to interface it to many different 118 | languages. 119 | 120 | **Example** (from the `SWIG website `__ ) 121 | 122 | The C code, ``example.c`` that has a variety of functions and variables 123 | 124 | .. code:: c 125 | 126 | #include 127 | double My_variable = 3.0; 128 | 129 | int fact(int n) { 130 | if (n <= 1) return 1; 131 | else return n*fact(n-1); 132 | } 133 | 134 | int my_mod(int x, int y) { 135 | return (x%y); 136 | } 137 | 138 | char *get_time() 139 | { 140 | time_t ltime; 141 | time(<ime); 142 | return ctime(<ime); 143 | } 144 | 145 | The interface file - this will remain the same irrespective of the 146 | language you want to port your C code to : 147 | 148 | :: 149 | 150 | /* example.i */ 151 | %module example 152 | %{ 153 | /* Put header files here or function declarations like below */ 154 | extern double My_variable; 155 | extern int fact(int n); 156 | extern int my_mod(int x, int y); 157 | extern char *get_time(); 158 | %} 159 | 160 | extern double My_variable; 161 | extern int fact(int n); 162 | extern int my_mod(int x, int y); 163 | extern char *get_time(); 164 | 165 | And now to compile it 166 | 167 | :: 168 | 169 | unix % swig -python example.i 170 | unix % gcc -c example.c example_wrap.c \ 171 | -I/usr/local/include/python2.1 172 | unix % ld -shared example.o example_wrap.o -o _example.so 173 | 174 | Finally, the Python output 175 | 176 | .. code:: python 177 | 178 | >>> import example 179 | >>> example.fact(5) 180 | 120 181 | >>> example.my_mod(7,3) 182 | 1 183 | >>> example.get_time() 184 | 'Sun Feb 11 23:01:07 1996' 185 | >>> 186 | 187 | As we can see, SWIG achieves the same result, but requires a slightly 188 | more involved effort. But it's worth it if you are targeting multiple 189 | languages. 190 | 191 | Python/C API 192 | --------------- 193 | 194 | The `C/Python API `__ is probably the 195 | most widely used method - not for its simplicity but for the fact that 196 | you can manipulate python objects in your C code. 197 | 198 | This method requires your C code to be specifically written for 199 | interfacing with Python code. All Python objects are represented as a 200 | PyObject struct and the ``Python.h`` header file provides various 201 | functions to manipulate it. For example if the PyObject is also a 202 | PyListType (basically a list), then we can use the ``PyList_Size()`` 203 | function on the struct to get the length of the list. This is equivalent 204 | to calling ``len(list)`` in python. Most of the basic 205 | functions/opertions that are there for native Python objects are made 206 | available in C via the ``Python.h`` header. 207 | 208 | **Example** 209 | 210 | To write a C extension that adds all the elements in a python list. (all elements are numbers) 211 | 212 | Let's start with the final interface we'd like to have, here is the 213 | python file that uses the C extension : 214 | 215 | .. code:: python 216 | 217 | #Though it looks like an ordinary python import, the addList module is implemented in C 218 | import addList 219 | 220 | l = [1,2,3,4,5] 221 | print "Sum of List - " + str(l) + " = " + str(addList.add(l)) 222 | 223 | The above looks like any ordinary python file, which imports and uses 224 | another python module called ``addList``. The only difference is that 225 | the addList module is not written in Python at all, but rather in C. 226 | 227 | Next we'll have a look at the C code that get's built into the 228 | ``addList`` Python module. This may seem a bit daunting at first, but 229 | once you understand the various components that go into writing the C 230 | file, it's pretty straightforward. 231 | 232 | *adder.c* 233 | 234 | .. code:: c 235 | 236 | //Python.h has all the required function definitions to manipulate the Python objects 237 | #include 238 | 239 | //This is the function that is called from your python code 240 | static PyObject* addList_add(PyObject* self, PyObject* args){ 241 | 242 | PyObject * listObj; 243 | 244 | //The input arguments come as a tuple, we parse the args to get the various variables 245 | //In this case it's only one list variable, which will now be referenced by listObj 246 | if (! PyArg_ParseTuple( args, "O", &listObj)) 247 | return NULL; 248 | 249 | //length of the list 250 | long length = PyList_Size(listObj); 251 | 252 | //iterate over all the elements 253 | long i, sum =0; 254 | for(i = 0; i < length; i++){ 255 | //get an element out of the list - the element is also a python objects 256 | PyObject* temp = PyList_GetItem(listObj, i); 257 | //we know that object represents an integer - so convert it into C long 258 | long elem = PyInt_AsLong(temp); 259 | sum += elem; 260 | } 261 | 262 | //value returned back to python code - another python object 263 | //build value here converts the C long to a python integer 264 | return Py_BuildValue("i", sum); 265 | } 266 | 267 | //This is the docstring that corresponds to our 'add' function. 268 | static char addList_docs[] = 269 | "add( ): add all elements of the list\n"; 270 | 271 | /* This table contains the relavent info mapping - 272 | , , 273 | , 274 | */ 275 | static PyMethodDef addList_funcs[] = { 276 | {"add", (PyCFunction)addList_add, METH_VARARGS, addList_docs}, 277 | {NULL, NULL, 0, NULL} 278 | }; 279 | 280 | /* 281 | addList is the module name, and this is the initialization block of the module. 282 | , , 283 | */ 284 | PyMODINIT_FUNC initaddList(void){ 285 | Py_InitModule3("addList", addList_funcs, 286 | "Add all ze lists"); 287 | } 288 | 289 | A step by step explanation : 290 | 291 | - The ```` file consists of all the required types (to represent Python object types) and function definitions (to operate on the python objects). 292 | - Next we write the function which we plan to call from python. Conventionally the function names are {module-name}\_{function-name}, which in this case is ``addList_add``. More about the function later. 293 | - Then fill in the info table - which contains all the relevant info of the functions we desire to have in the module. Every row corresponds to a function, with the last one being a sentinel value (row of null elements). 294 | - Finally the module initialization block which is of the signature ``PyMODINIT_FUNC init{module-name}``. 295 | 296 | The function ``addList_add`` accepts arguments as a PyObject type struct 297 | (args is also a tuple type - but since everything in python is an 298 | object, we use the generic PyObject notion). The incoming arguments is 299 | parsed (basically split the tuple into individual elements) by 300 | ``PyArg_ParseTuple()``. The first parameter is the argument variable to 301 | be parsed. The second argument is a string that tells us how to parse 302 | each element in the args tuple. The character in the Nth position of the 303 | string tells us the type of the Nth element in the args tuple, example - 304 | 'i' would mean integer, 's' would mean string and 'O' would mean a 305 | Python object. Next multiple arguments follow, these are where you would 306 | like the ``PyArg_ParseTuple()`` function to store all the elements that 307 | it has parsed. The number of such arguments is equal to the number of 308 | arguments which the module function expects to receive, and positional 309 | integrity is maintained. For example if we expected a string, integer 310 | and a python list in that order, the function signature would be 311 | 312 | .. code:: c 313 | 314 | int n; 315 | char *s; 316 | PyObject* list; 317 | PyArg_ParseTuple(args, "siO", &s, &n, &list); 318 | 319 | In this case we only have to extract a list object, and store it in the 320 | variable ``listObj``. We then use the ``PyList_Size()`` function on our 321 | list object and get the length. This is similar to how you would call 322 | ``len(list)`` in python. 323 | 324 | Now we loop through the list, get each element using the 325 | ``PyList_GetItem(list, index)`` function. This returns a PyObject\*. But 326 | since we know that the Python objects are also ``PyIntType``, we just 327 | use the ``PyInt_AsLong(PyObj *)`` function to get the required value. We 328 | do this for every element and finally get the sum. 329 | 330 | The sum is converted to a python object and is returned to the Python 331 | code with the help of ``Py_BuildValue()``. Here the "i" indicates that 332 | the value we want to build is a python integer object. 333 | 334 | Now we build the C module. Save the following code as ``setup.py`` 335 | 336 | .. code:: python 337 | 338 | #build the modules 339 | 340 | from distutils.core import setup, Extension 341 | 342 | setup(name='addList', version='1.0', \ 343 | ext_modules=[Extension('addList', ['adder.c'])]) 344 | 345 | and run 346 | 347 | .. code:: sh 348 | 349 | python setup.py install 350 | 351 | This should now build and install the C file into the python module we 352 | desire. 353 | 354 | After all this hard work, we'll now test if the module works - 355 | 356 | .. code:: python 357 | 358 | #module that talks to the C code 359 | import addList 360 | 361 | l = [1,2,3,4,5] 362 | print "Sum of List - " + str(l) + " = " + str(addList.add(l)) 363 | 364 | And here is the output 365 | 366 | :: 367 | 368 | Sum of List - [1, 2, 3, 4, 5] = 15 369 | 370 | So as you can see, we have developed our first successful C Python 371 | extension using the Python.h API. This method does seem complex at 372 | first, but once you get used to it it can prove to be quite useful. 373 | 374 | Other ways to interface C code to Python is to use an alternative and 375 | faster build of python - `Cython `__. But Cython is 376 | a slightly different language than the main stream python we see. Hence 377 | that method is not covered here. 378 | -------------------------------------------------------------------------------- /python_modules_in_c.rst: -------------------------------------------------------------------------------- 1 | Python Modules in C 2 | ------------------- 3 | 4 | We all know that Python can be slow at times. If you are using it to do 5 | some resource intensive task then it can be a major bottleneck. What 6 | options do we have of making it fast apart from code optimisation? 7 | Fortunately Python has a solution for us. It allows us to interface with 8 | C code easily and write extensions for critical parts in C. This allows 9 | to provide a speed boost to our Python code. 10 | 11 | There are already a couple of modules which have been rewritten in C for 12 | the sake of speed. They include cPickle, cProfile and c 13 | -------------------------------------------------------------------------------- /set_-_data_structure.rst: -------------------------------------------------------------------------------- 1 | ``set`` Data Structure 2 | ---------------------- 3 | 4 | ``set`` is a really useful data structure. ``sets`` behave mostly like 5 | lists with the distinction that they can not contain duplicate values. 6 | It is really useful in a lot of cases. For instance you might want to 7 | check whether there are duplicates in a list or not. You have two 8 | options. The first one involves using a ``for`` loop. Something like 9 | this: 10 | 11 | .. code:: python 12 | 13 | some_list = ['a', 'b', 'c', 'b', 'd', 'm', 'n', 'n'] 14 | 15 | duplicates = [] 16 | for value in some_list: 17 | if some_list.count(value) > 1: 18 | if value not in duplicates: 19 | duplicates.append(value) 20 | 21 | print(duplicates) 22 | # Output: ['b', 'n'] 23 | 24 | But there is a simpler and more elegant solution involving ``sets``. You 25 | can simply do something like this: 26 | 27 | .. code:: python 28 | 29 | some_list = ['a', 'b', 'c', 'b', 'd', 'm', 'n', 'n'] 30 | duplicates = set([x for x in some_list if some_list.count(x) > 1]) 31 | print(duplicates) 32 | # Output: set(['b', 'n']) 33 | 34 | Sets also have a few other methods. Below are some of them. 35 | 36 | **Intersection** 37 | 38 | You can intersect two sets. For instance: 39 | 40 | .. code:: python 41 | 42 | valid = set(['yellow', 'red', 'blue', 'green', 'black']) 43 | input_set = set(['red', 'brown']) 44 | print(input_set.intersection(valid)) 45 | # Output: set(['red']) 46 | 47 | **Difference** 48 | 49 | You can find the invalid values in the above example using the 50 | difference method. For example: 51 | 52 | .. code:: python 53 | 54 | valid = set(['yellow', 'red', 'blue', 'green', 'black']) 55 | input_set = set(['red', 'brown']) 56 | print(input_set.difference(valid)) 57 | # Output: set(['brown']) 58 | 59 | You can also create sets using the new notation: 60 | 61 | .. code:: python 62 | 63 | a_set = {'red', 'blue', 'green'} 64 | print(type(a_set)) 65 | # Output: 66 | 67 | There are a few other methods as well. I would recommend visiting the 68 | official documentation and giving it a quick read. 69 | -------------------------------------------------------------------------------- /targeting_python_2_3.rst: -------------------------------------------------------------------------------- 1 | Targeting Python 2+3 2 | -------------------- 3 | 4 | In a lot of cases you might want to develop programs which can be run in 5 | both Python 2+ and 3+. 6 | 7 | Just imagine that you have a very popular Python module which is used by 8 | hundreds of people but not all of them have the same version of Python (2 or 3). In that case 9 | you have two choices. The first one is to distribute 2 modules, one for 10 | Python 2 and the other for Python 3. The other choice is to modify your 11 | current code and make it compatible with both Python 2 and 3. 12 | 13 | In this section I am going to highlight some of the tricks which you can 14 | employ to make a script compatible with both of them. 15 | 16 | **Future imports** 17 | 18 | The first and most important method is to use ``__future__`` imports. It 19 | allows you to import Python 3 functionality in Python 2. Here are a couple 20 | examples: 21 | 22 | Context managers were new in Python 2.6+. For using them in Python 2.5 you can use: 23 | 24 | .. code:: python 25 | 26 | from __future__ import with_statement 27 | 28 | ``print`` was changed to a function in Python 3. If you want to use it 29 | in Python 2 you can import it from ``__future__``: 30 | 31 | .. code:: python 32 | 33 | print 34 | # Output: 35 | 36 | from __future__ import print_function 37 | print(print) 38 | # Output: 39 | 40 | **Dealing with module renaming** 41 | 42 | First, tell me how you import packages in your script ? Most of us do 43 | this : 44 | 45 | .. code:: python 46 | 47 | import foo 48 | # or 49 | from foo import bar 50 | 51 | Do you know that you can do something like this as well? 52 | 53 | .. code:: python 54 | 55 | import foo as foo 56 | 57 | I know its function is the same as the above listed code but it is vital 58 | for making your script compatible with Python 2 and 3. Now examine the 59 | code below : 60 | 61 | .. code:: python 62 | 63 | try: 64 | import urllib.request as urllib_request # for Python 3 65 | except ImportError: 66 | import urllib2 as urllib_request # for Python 2 67 | 68 | So let me explain the above code a little. We are wrapping our importing 69 | code in a ``try/except`` clause. We are doing it because in Python 2 there is 70 | no ``urllib.request`` module so this would result in an ``ImportError``. The 71 | functionality of ``urllib.request`` is provided by the ``urllib2`` module in 72 | Python 2. So, when using Python 2, we try to import ``urllib.request`` and 73 | if we get an ``ImportError`` then we tell Python to import ``urllib2`` instead. 74 | 75 | The final thing you need to know about is the ``as`` keyword. It is 76 | mapping the imported module to ``urllib_request``. So that all of 77 | the classes and methods within ``urllib2`` are available to us via the alias 78 | ``urllib_request``. 79 | 80 | **Obsolete Python 2 builtins** 81 | 82 | Another thing to keep in mind is that there are 12 Python 2 builtins 83 | which have been removed from Python 3. Make sure that you don't use them 84 | in Python 2 in order to make your code compatible with Python 3. 85 | Here is a way to enforce that you abandon these 12 builtins in Python 2 as 86 | well: 87 | 88 | .. code:: python 89 | 90 | from future.builtins.disabled import * 91 | 92 | Now whenever you try to use the modules which are abandoned in Python 3, 93 | it raises a ``NameError`` like this: 94 | 95 | .. code:: python 96 | 97 | from future.builtins.disabled import * 98 | 99 | apply() 100 | # Output: NameError: obsolete Python 2 builtin apply is disabled 101 | 102 | **External standard-library backports** 103 | 104 | There are a few packages in the wild which provide Python 3 105 | functionality in Python 2. For instance, we have: 106 | 107 | - enum ``pip install enum34`` 108 | - singledispatch ``pip install singledispatch`` 109 | - pathlib ``pip install pathlib`` 110 | 111 | For further reading, the Python documentation has a `comprehensive guide 112 | `_ of steps you need to 113 | take to make your code compatible with both Python 2 and 3. 114 | -------------------------------------------------------------------------------- /ternary_operators.rst: -------------------------------------------------------------------------------- 1 | Ternary Operators 2 | ----------------- 3 | 4 | Ternary operators are more commonly known as conditional expressions in 5 | Python. These operators evaluate something based on a condition being 6 | true or not. They became a part of Python in version 2.4 7 | 8 | Here is a blueprint and an example of using these conditional 9 | expressions. 10 | 11 | **Blueprint:** 12 | 13 | .. code:: python 14 | 15 | value_if_true if condition else value_if_false 16 | 17 | **Example:** 18 | 19 | .. code:: python 20 | 21 | is_nice = True 22 | state = "nice" if is_nice else "not nice" 23 | 24 | It allows to quickly test a condition instead of a multiline if 25 | statement. Often times it can be immensely helpful and can make your 26 | code compact but still maintainable. 27 | 28 | Another more obscure and not widely used example involves tuples. Here 29 | is some sample code: 30 | 31 | **Blueprint:** 32 | 33 | .. code:: python 34 | 35 | (if_test_is_false, if_test_is_true)[test] 36 | 37 | **Example:** 38 | 39 | .. code:: python 40 | 41 | nice = True 42 | personality = ("mean", "nice")[nice] 43 | print("The cat is ", personality) 44 | # Output: The cat is nice 45 | 46 | This works simply because True == 1 and False == 0, and so can be done 47 | with lists in addition to tuples. 48 | 49 | The above example is not widely used and is generally disliked by 50 | Pythonistas for not being Pythonic. It is also easy to confuse where to 51 | put the true value and where to put the false value in the tuple. 52 | 53 | Another reason to avoid using a tupled ternery is that it results in 54 | both elements of the tuple being evaluated, whereas the if-else 55 | ternary operator does not. 56 | 57 | **Example:** 58 | 59 | .. code:: python 60 | 61 | condition = True 62 | print(2 if condition else 1/0) 63 | #Output is 2 64 | 65 | print((1/0, 2)[condition]) 66 | #ZeroDivisionError is raised 67 | 68 | This happens because with the tupled ternary technique, the tuple is 69 | first built, then an index is found. For the if-else ternary operator, 70 | it follows the normal if-else logic tree. Thus, if one case could 71 | raise an exception based on the condition, or if either case is a 72 | computation-heavy method, using tuples is best avoided. 73 | 74 | 75 | **ShortHand Ternary** 76 | 77 | In python there is also the shorthand ternary tag which is a shorter version of the 78 | normal ternary operator you have seen above. 79 | 80 | Syntax was introduced in Python 2.5 and can be used in python 2.5 or greater. 81 | 82 | **Example** 83 | 84 | .. code:: python 85 | 86 | >>> True or "Some" 87 | True 88 | >>> 89 | >>> False or "Some" 90 | 'Some' 91 | 92 | The first statement (`True or "Some"`) will return `True` and the second statement (`False or "Some"`) will return `Some`. 93 | 94 | This is helpful in case where you quickly want to check for the output of a function and give a useful message if the output is empty: 95 | 96 | .. code:: python 97 | 98 | >>> output = None 99 | >>> msg = output or "No data returned" 100 | >>> print(msg) 101 | No data returned 102 | 103 | Or as a simple way to define function parameters with dynamic default values: 104 | 105 | .. code:: python 106 | 107 | >>> def my_function(real_name, optional_display_name=None): 108 | >>> optional_display_name = optional_display_name or real_name 109 | >>> print(optional_display_name) 110 | >>> my_function("John") 111 | John 112 | >>> my_function("Mike", "anonymous123") 113 | anonymous123 114 | -------------------------------------------------------------------------------- /virtual_environment.rst: -------------------------------------------------------------------------------- 1 | Virtual Environment 2 | ------------------- 3 | 4 | Have you ever heard of ``virtualenv``? If you are a beginner, 5 | then you might not have heard about it but if you are a 6 | seasoned programmer then it may well be a vital part of your toolset. 7 | 8 | So what is ``virtualenv``? ``Virtualenv`` is a tool which allows us to 9 | make isolated python environments. Imagine you have an application that 10 | needs version 2 of a library, but another application requires 11 | version 3. How can you use and develop both these applications? 12 | 13 | If you install everything into ``/usr/lib/python2.7/site-packages`` (or 14 | whatever your platform's standard location is), it's easy to end up in a 15 | situation where you unintentionally upgrade a package. 16 | 17 | In another case, imagine that you have an application which is fully 18 | developed and you do not want to make any change to the libraries it is 19 | using but at the same time you start developing another application 20 | which requires the updated versions of those libraries. 21 | 22 | What will you do? Use ``virtualenv``! It creates isolated environments 23 | for your python application and allows you to install Python libraries 24 | in that isolated environment instead of installing them globally. 25 | 26 | To install it, just type this command in the shell: 27 | 28 | .. code:: python 29 | 30 | $ pip install virtualenv 31 | 32 | The most important commands are: 33 | 34 | - ``$ virtualenv myproject`` 35 | - ``$ source myproject/bin/activate`` 36 | 37 | This first one makes an isolated virtualenv environment in the 38 | ``myproject`` folder and the second command activates that isolated 39 | environment. 40 | 41 | While creating the virtualenv you have to make a decision. Do you 42 | want this virtualenv to use packages from your system ``site-packages`` 43 | or install them in the virtualenv’s site-packages? By default, 44 | virtualenv will not give access to the global ``site-packages``. 45 | 46 | If you want your ``virtualenv`` to have access to your systems 47 | ``site-packages``, use the ``--system-site-packages`` switch when creating 48 | your virtualenv like this: 49 | 50 | .. code:: python 51 | 52 | $ virtualenv --system-site-packages mycoolproject 53 | 54 | You can turn off the ``env`` by typing: 55 | 56 | .. code:: python 57 | 58 | $ deactivate 59 | 60 | Running `python` after deactivating will use your system installation 61 | of Python again. 62 | 63 | **Bonus** 64 | 65 | You can use ``smartcd`` which is a library for bash and zsh and allows 66 | you to alter your bash (or zsh) environment as you cd. It can be really 67 | helpful to activate and deactivate a ``virtualenv`` when you change 68 | directories. I have used it quite a lot and love it. You can read more 69 | about it on `GitHub `__ 70 | 71 | This was just a short intro to virtualenv. There's a lot more to it; `this 72 | link `__ has more 73 | information. 74 | -------------------------------------------------------------------------------- /zip.rst: -------------------------------------------------------------------------------- 1 | Zip and unzip 2 | ------------- 3 | 4 | **Zip** 5 | 6 | Zip is a useful function that allows you to combine two lists easily. 7 | 8 | After calling zip, an iterator is returned. In order to see the content wrapped inside, we need to first convert it to a list. 9 | 10 | Example: 11 | 12 | .. code:: python 13 | 14 | first_name = ['Joe','Earnst','Thomas','Martin','Charles'] 15 | 16 | last_name = ['Schmoe','Ehlmann','Fischer','Walter','Rogan','Green'] 17 | 18 | age = [23, 65, 11, 36, 83] 19 | 20 | print(list(zip(first_name,last_name, age))) 21 | 22 | # Output 23 | # 24 | # [('Joe', 'Schmoe', 23), ('Earnst', 'Ehlmann', 65), ('Thomas', 'Fischer', 11), ('Martin', 'Walter', 36), ('Charles', 'Rogan', 83)] 25 | 26 | One advantage of zip is that it improves readability of for loops. 27 | 28 | For example, instead of needing multiple inputs, you only need one zipped list for the following for loop: 29 | 30 | .. code:: python 31 | 32 | first_name = ['Joe','Earnst','Thomas','Martin','Charles'] 33 | last_name = ['Schmoe','Ehlmann','Fischer','Walter','Rogan','Green'] 34 | age = [23, 65, 11, 36, 83] 35 | 36 | for first_name, last_name, age in zip(first_name, last_name, age): 37 | print(f"{first_name} {last_name} is {age} years old") 38 | 39 | # Output 40 | # 41 | # Joe Schmoe is 23 years old 42 | # Earnst Ehlmann is 65 years old 43 | # Thomas Fischer is 11 years old 44 | # Martin Walter is 36 years old 45 | # Charles Rogan is 83 years old 46 | 47 | **Unzip** 48 | 49 | We can use the `zip` function to unzip a list as well. This time, we need an input of a list with an asterisk before it. 50 | 51 | The outputs are the separated lists. 52 | 53 | Example: 54 | 55 | .. code:: python 56 | 57 | full_name_list = [('Joe', 'Schmoe', 23), 58 | ('Earnst', 'Ehlmann', 65), 59 | ('Thomas', 'Fischer', 11), 60 | ('Martin', 'Walter', 36), 61 | ('Charles', 'Rogan', 83)] 62 | 63 | first_name, last_name, age = list(zip(*full_name_list)) 64 | print(f"first name: {first_name}\nlast name: {last_name} \nage: {age}") 65 | 66 | # Output 67 | 68 | # first name: ('Joe', 'Earnst', 'Thomas', 'Martin', 'Charles') 69 | # last name: ('Schmoe', 'Ehlmann', 'Fischer', 'Walter', 'Rogan') 70 | # age: (23, 65, 11, 36, 83) 71 | 72 | --------------------------------------------------------------------------------