├── images ├── key.png ├── geany.png ├── idle.png ├── iters.png ├── people.png ├── py-exe.png ├── drawings.odg ├── idle-new.png ├── modules.png ├── samelist.png ├── slicing1.png ├── slicing2.png ├── slicing3.png ├── terminal.png ├── download-me.png ├── freeze-melt.png ├── generators.png ├── indexing1.png ├── indexing2.png ├── indexing3.png ├── powershell.png ├── variables1.png ├── variables2.png ├── differentlist.png ├── discord-explore.png └── locals-and-globals.png ├── .gitignore ├── html-style.css ├── advanced ├── answers.md ├── README.md ├── magicmethods.md ├── functions.md ├── datatypes.md └── iters.md ├── classes.md ├── contact-me.md ├── basics ├── README.md ├── the-way-of-the-program.md ├── installing-python.md ├── editor-setup.md ├── what-is-true.md ├── getting-started.md ├── zip-and-enumerate.md ├── using-functions.md ├── larger-program.md ├── what-is-programming.md ├── if.md ├── variables.md ├── docstrings.md ├── dicts.md ├── lists-and-tuples.md └── handy-stuff-strings.md ├── what-next.md ├── TODO.md ├── LICENSE ├── getting-help.md ├── update-readmes.py ├── update-ends.py ├── README.md ├── linkcheck.py ├── common.py └── make-html.py /images/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/key.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # generated html files 2 | html/ 3 | 4 | # python cache files 5 | __pycache__/ 6 | -------------------------------------------------------------------------------- /images/geany.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/geany.png -------------------------------------------------------------------------------- /images/idle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/idle.png -------------------------------------------------------------------------------- /images/iters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/iters.png -------------------------------------------------------------------------------- /images/people.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/people.png -------------------------------------------------------------------------------- /images/py-exe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/py-exe.png -------------------------------------------------------------------------------- /images/drawings.odg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/drawings.odg -------------------------------------------------------------------------------- /images/idle-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/idle-new.png -------------------------------------------------------------------------------- /images/modules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/modules.png -------------------------------------------------------------------------------- /images/samelist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/samelist.png -------------------------------------------------------------------------------- /images/slicing1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/slicing1.png -------------------------------------------------------------------------------- /images/slicing2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/slicing2.png -------------------------------------------------------------------------------- /images/slicing3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/slicing3.png -------------------------------------------------------------------------------- /images/terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/terminal.png -------------------------------------------------------------------------------- /images/download-me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/download-me.png -------------------------------------------------------------------------------- /images/freeze-melt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/freeze-melt.png -------------------------------------------------------------------------------- /images/generators.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/generators.png -------------------------------------------------------------------------------- /images/indexing1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/indexing1.png -------------------------------------------------------------------------------- /images/indexing2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/indexing2.png -------------------------------------------------------------------------------- /images/indexing3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/indexing3.png -------------------------------------------------------------------------------- /images/powershell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/powershell.png -------------------------------------------------------------------------------- /images/variables1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/variables1.png -------------------------------------------------------------------------------- /images/variables2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/variables2.png -------------------------------------------------------------------------------- /images/differentlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/differentlist.png -------------------------------------------------------------------------------- /images/discord-explore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/discord-explore.png -------------------------------------------------------------------------------- /images/locals-and-globals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dr-mushtaq/python-tutorial/master/images/locals-and-globals.png -------------------------------------------------------------------------------- /html-style.css: -------------------------------------------------------------------------------- 1 | /* This file is used by the HTML files that make-html.py creates. 2 | Customize this if you want to create HTML files with different 3 | colors. See also make-html.py's --pygments-style option. */ 4 | body { 5 | color: white; 6 | background-color: #222222; 7 | } 8 | a { 9 | color: orange; 10 | } 11 | -------------------------------------------------------------------------------- /advanced/answers.md: -------------------------------------------------------------------------------- 1 | 2 | *** 3 | 4 | If you have trouble with this tutorial, please 5 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 6 | or [ask for help online](../getting-help.md). 7 | If you like this tutorial, please [give it a 8 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 9 | 10 | You may use this tutorial freely at your own risk. See 11 | [LICENSE](../LICENSE). 12 | 13 | [List of contents](../README.md#list-of-contents) 14 | -------------------------------------------------------------------------------- /classes.md: -------------------------------------------------------------------------------- 1 | This file has been moved [here](basics/classes.md). 2 | 3 | *** 4 | 5 | If you have trouble with this tutorial, please 6 | [tell me about it](./contact-me.md) and I'll make this tutorial better, 7 | or [ask for help online](./getting-help.md). 8 | If you like this tutorial, please [give it a 9 | star](./README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 10 | 11 | You may use this tutorial freely at your own risk. See 12 | [LICENSE](./LICENSE). 13 | 14 | [List of contents](./README.md#list-of-contents) 15 | -------------------------------------------------------------------------------- /contact-me.md: -------------------------------------------------------------------------------- 1 | # Contact me 2 | 3 | If you have any trouble with the tutorial or you would like to improve 4 | it, there are a few ways to contact me: 5 | 6 | - Create an issue on GitHub. 7 | 8 | This is probably the best choice if you had trouble following the 9 | tutorial, and something in it should be explained better. Click 10 | [here](https://github.com/Akuli/python-tutorial/issues/new) to 11 | create an issue. You will be asked to create a GitHub account if you 12 | don't already have one. 13 | 14 | - Tell me on IRC. 15 | 16 | I'm regularly on ##learnpython on libera. See 17 | [Getting help](getting-help.md) for instructions to getting there. 18 | 19 | *** 20 | 21 | If you have trouble with this tutorial, please 22 | [tell me about it](./contact-me.md) and I'll make this tutorial better, 23 | or [ask for help online](./getting-help.md). 24 | If you like this tutorial, please [give it a 25 | star](./README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 26 | 27 | You may use this tutorial freely at your own risk. See 28 | [LICENSE](./LICENSE). 29 | 30 | [List of contents](./README.md#list-of-contents) 31 | -------------------------------------------------------------------------------- /advanced/README.md: -------------------------------------------------------------------------------- 1 | [comment]: # (This file is automatically generated. Don't edit this) 2 | [comment]: # (file manually, run update-readmes.py instead.) 3 | 4 | # Advanced 5 | 6 | If you want to learn more advanced techniques, you can also read this 7 | section. Most of the techniques explained here are great when you're 8 | working on a large project, and your code would be really repetitive 9 | without these things. 10 | 11 | You can experiment with these things freely, but please **don't use these 12 | techniques just because you know how to use them.** Prefer the simple 13 | techniques from the Basics part instead when possible. Simple is better 14 | than complex. 15 | 16 | 1. [Handy data types](datatypes.md) 17 | 2. [Advanced stuff with functions](functions.md) 18 | 3. [Magic methods](magicmethods.md) 19 | 4. [Iterables, iterators and generators](iters.md) 20 | 21 | *** 22 | 23 | If you have trouble with this tutorial, please 24 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 25 | or [ask for help online](../getting-help.md). 26 | If you like this tutorial, please [give it a 27 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 28 | 29 | You may use this tutorial freely at your own risk. See 30 | [LICENSE](../LICENSE). 31 | 32 | [List of contents](../README.md#list-of-contents) 33 | -------------------------------------------------------------------------------- /basics/README.md: -------------------------------------------------------------------------------- 1 | [comment]: # (This file is automatically generated. Don't edit this) 2 | [comment]: # (file manually, run update-readmes.py instead.) 3 | 4 | # Basics 5 | 6 | This section will get you started with using Python and you'll be able 7 | to learn more about whatever you want after studying it. 8 | 9 | 1. [What is programming?](what-is-programming.md) 10 | 2. [Installing Python](installing-python.md) 11 | 3. [Getting started with Python](getting-started.md) 12 | 4. [ThinkPython: The way of the program](the-way-of-the-program.md) 13 | 5. [Variables, Booleans and None](variables.md) 14 | 6. [Using functions](using-functions.md) 15 | 7. [Setting up an editor](editor-setup.md) 16 | 8. [If, else and elif](if.md) 17 | 9. [Handy stuff with strings](handy-stuff-strings.md) 18 | 10. [Lists and tuples](lists-and-tuples.md) 19 | 11. [Loops](loops.md) 20 | 12. [zip and enumerate](zip-and-enumerate.md) 21 | 13. [Dictionaries](dicts.md) 22 | 14. [Defining functions](defining-functions.md) 23 | 15. [Writing a larger program](larger-program.md) 24 | 16. [What is true?](what-is-true.md) 25 | 17. [Files](files.md) 26 | 18. [Modules](modules.md) 27 | 19. [Exceptions](exceptions.md) 28 | 20. [Classes](classes.md) 29 | 21. [Docstrings](docstrings.md) 30 | 31 | *** 32 | 33 | If you have trouble with this tutorial, please 34 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 35 | or [ask for help online](../getting-help.md). 36 | If you like this tutorial, please [give it a 37 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 38 | 39 | You may use this tutorial freely at your own risk. See 40 | [LICENSE](../LICENSE). 41 | 42 | [List of contents](../README.md#list-of-contents) 43 | -------------------------------------------------------------------------------- /what-next.md: -------------------------------------------------------------------------------- 1 | # What should I do now? 2 | 3 | You are now at the end of this tutorial. This means that you're almost 4 | ready to do something fun with Python. This page contains a bunch of 5 | links to other useful and fun Python resources. 6 | 7 | ## What the heck is this? 8 | 9 | Sometimes you'll come across things that I haven't shown in this 10 | tutorial. Here's a table of things you'll probably come across: 11 | 12 | ### A dictionary without a `:` 13 | 14 | These are actually [sets](https://docs.python.org/3/tutorial/datastructures.html#sets), 15 | not dictionaries. However, `{}` is a dictionary. 16 | 17 | ### yield stuff 18 | 19 | The [yield keyword](http://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do) 20 | is a way to create generators 21 | 22 | | What you see | What it is | 23 | |---------------------------|---------------------------------------------------------------------------------------------------| 24 | | a dictionary without `:` | [a set] | 25 | | yield stuff | | 26 | | `import stuff as thing` | imports stuff and sets the module to a thing variable | 27 | | `from stuff import thing` | about the same as `import stuff` and after that 28 | | `from stuff import *` | imports everything 29 | 30 | ## Fun modules 31 | 32 | *** 33 | 34 | If you have trouble with this tutorial, please 35 | [tell me about it](./contact-me.md) and I'll make this tutorial better, 36 | or [ask for help online](./getting-help.md). 37 | If you like this tutorial, please [give it a 38 | star](./README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 39 | 40 | You may use this tutorial freely at your own risk. See 41 | [LICENSE](./LICENSE). 42 | 43 | [List of contents](./README.md#list-of-contents) 44 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Stuff that will (hopefully) be added to this tutorial 2 | 3 | This tutorial is not complete. It still needs: 4 | 5 | - replacement for the thinkpython linking file 6 | - what is a type and why it matters 7 | - also add `type()` calls to other places, especially when 8 | introducing tuples (thanks kodec), functions and modules 9 | - `3.14` and `'3.14'` 10 | - `# 'hello'` and `'# hello'` 11 | - range somewhere 12 | - **More exercises and examples everywhere!** 13 | - especially "fix this" exercises 14 | - classes part 1: 15 | 16 | Akuli: I would probably add an example of refactoring 17 | a bunch of functions working with shared global data 18 | into a class because it's a pretty typical usecase 19 | 20 | - classes part 2 21 | - non-public `_variables` 22 | - "singular" inheritance, inheritance of built-in classes 23 | - using super 24 | - advise to avoid multiple inheritance 25 | - last chapter: "What should I do now?" links to other resources 26 | - first of all: read zen and pep8 27 | - explanation of the zen, especially the "one right way" myth 28 | - GUI programming tutorials 29 | - easygui 30 | - tkinter in effbot (warn the readers about star imports) 31 | - pyqt5 in zetcode (warn about mixedCase) 32 | - gtk+ 3 in readthedocs 33 | - a pygame tutorial 34 | - David Beazley's metaprogramming and other talks 35 | - "What the heck is this?" section for stuff i haven't talked about 36 | - regexes 37 | 38 | - add a screenshot about geany's running settings to 39 | basics/editor-setup.md 40 | 41 | *** 42 | 43 | If you have trouble with this tutorial, please 44 | [tell me about it](./contact-me.md) and I'll make this tutorial better, 45 | or [ask for help online](./getting-help.md). 46 | If you like this tutorial, please [give it a 47 | star](./README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 48 | 49 | You may use this tutorial freely at your own risk. See 50 | [LICENSE](./LICENSE). 51 | 52 | [List of contents](./README.md#list-of-contents) 53 | -------------------------------------------------------------------------------- /basics/the-way-of-the-program.md: -------------------------------------------------------------------------------- 1 | # ThinkPython: The way of the program 2 | 3 | ThinkPython is a free Python book. Its first chapter is about 4 | programming in general. [Read it 5 | here.](http://greenteapress.com/thinkpython2/html/thinkpython2002.html). 6 | 7 | Read the glossary also, but don't study it too much. Some things in it 8 | are useful to know, but I think studying it carefully would be really 9 | boring. Also do all exercises except the last one. It's more about 10 | math skills than learning Python. 11 | 12 | When you're done reading, read the summary below and make sure you've 13 | learned everything. 14 | 15 | ## Summary 16 | 17 | - Now you should have some kind of idea about what programming is. 18 | - Each value has a type, and you can find that out with `type(value)`. 19 | For example, writing `type(123)` to the Python prompt does the same 20 | thing as writing `int` to the prompt. 21 | - Types and classes are the same thing (in Python 3). 22 | - Some of the most commonly used types are: 23 | - int is short for integer. `1` and `2` are integers. 24 | - float is short for floating point number. `1.0` and `3.14` are 25 | floats. 26 | - str is short for string. `"hello"` and `'hello'` are strings. It 27 | doesn't matter if you use 'single quotes' or "double quotes", 28 | they do the same thing in Python. 29 | 30 | ## More exercises 31 | 32 | 1. What happens if you use + between two strings, like 33 | `"hello" + "world"`? How about `"hello" * "world"`? 34 | 2. What happens if you use + between a string and an integer, like 35 | `"hello" + 3`? How about `"hello" * 3`? 36 | 3. What happens if you use + between a float and an integer, like 37 | `0.5 + 3`? How about `0.5 * 3`? 38 | 39 | *** 40 | 41 | If you have trouble with this tutorial, please 42 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 43 | or [ask for help online](../getting-help.md). 44 | If you like this tutorial, please [give it a 45 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 46 | 47 | You may use this tutorial freely at your own risk. See 48 | [LICENSE](../LICENSE). 49 | 50 | [Previous](getting-started.md) | [Next](variables.md) | 51 | [List of contents](../README.md#basics) 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The instructions and text in this tutorial (the "software") are licensed 2 | under the zlib License. 3 | 4 | (C) 2016-2021 Akuli 5 | 6 | This software is provided 'as-is', without any express or implied 7 | warranty. In no event will the authors be held liable for any damages 8 | arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, 11 | including commercial applications, and to alter it and redistribute it 12 | freely, subject to the following restrictions: 13 | 14 | 1. The origin of this software must not be misrepresented; you must not 15 | claim that you wrote the original software. If you use this software 16 | in a product, an acknowledgment in the product documentation would be 17 | appreciated but is not required. 18 | 2. Altered source versions must be plainly marked as such, and must not be 19 | misrepresented as being the original software. 20 | 3. This notice may not be removed or altered from any source distribution. 21 | 22 | 23 | 24 | The code examples (the "software") are unlicensed: 25 | 26 | This is free and unencumbered software released into the public domain. 27 | 28 | Anyone is free to copy, modify, publish, use, compile, sell, or 29 | distribute this software, either in source code form or as a compiled 30 | binary, for any purpose, commercial or non-commercial, and by any 31 | means. 32 | 33 | In jurisdictions that recognize copyright laws, the author or authors 34 | of this software dedicate any and all copyright interest in the 35 | software to the public domain. We make this dedication for the benefit 36 | of the public at large and to the detriment of our heirs and 37 | successors. We intend this dedication to be an overt act of 38 | relinquishment in perpetuity of all present and future rights to this 39 | software under copyright law. 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 42 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 43 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 44 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 45 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 46 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 47 | OTHER DEALINGS IN THE SOFTWARE. 48 | 49 | For more information, please refer to 50 | -------------------------------------------------------------------------------- /getting-help.md: -------------------------------------------------------------------------------- 1 | # Getting help 2 | 3 | When you have a problem with Python, you're not alone! There are many 4 | places to ask for help in. 5 | 6 | Regardless of where you ask for help, please: 7 | - Don't ask "does someone know ...". Just ask about your problem right away. 8 | - Make your question short. 9 | - Include everything that other people will need to answer your question. 10 | For example, if you are getting an error, include your code and the error message. 11 | 12 | 13 | ## IRC 14 | 15 | IRC is the oldest chatting service I know, but as of 2022, it's still 16 | in use, and a good way to get help in Python. 17 | An advantage with IRC is that you don't need to create an account to use it. 18 | 19 | To get started, go to https://web.libera.chat/ and type `##learnpython` or `#python` for the channel name. 20 | 21 | - `##learnpython` is a channel where I am regularly, but there's usually only about 20 people there, 22 | so it could be that nobody answers your question, depending on what time it is. 23 | I'm on `##learnpython` at about 7PM to 10PM UTC. 24 | If you see `Akuli` in the user list, that's me :) 25 | - `#python` is an active channel that I don't use much, but someone will likely answer your question pretty quickly. 26 | 27 | If you want to post more than 3 lines of code, 28 | put it to [dpaste.com](https://dpaste.com/) first. 29 | Just copy-paste your code to the big text area and click the "Paste it" 30 | button, and then post a link to your paste on IRC. 31 | Otherwise every line of your code will appear as a separate message on IRC, 32 | so if your code is 15 lines, just pasting it in will produce 15 different messages. 33 | This would be annoying. 34 | 35 | 36 | ## Discord 37 | 38 | If you have a discord account, you can click the "Explore Public Servers" button at bottom left. 39 | 40 | ![Discord's explore public servers button](images/discord-explore.png) 41 | 42 | You can then search for e.g. Python, and you should find many servers to choose from. 43 | I am currently @Akuli on a server called "The Programmer's Hangout". 44 | 45 | 46 | ## Websites to ask help on 47 | 48 | Personally, I've never asked a question on any of these sites. Getting 49 | help on IRC is much faster. 50 | 51 | - [stackoverflow](https://stackoverflow.com/) is a question/answer site 52 | for programmers. Search for your question first, maybe someone has 53 | already asked that and it has been answered. 54 | - [The learnpython subreddit](https://www.reddit.com/r/learnpython/) 55 | is another good place to ask Python questions on. 56 | 57 | *** 58 | 59 | If you have trouble with this tutorial, please 60 | [tell me about it](./contact-me.md) and I'll make this tutorial better, 61 | or [ask for help online](./getting-help.md). 62 | If you like this tutorial, please [give it a 63 | star](./README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 64 | 65 | You may use this tutorial freely at your own risk. See 66 | [LICENSE](./LICENSE). 67 | 68 | [List of contents](./README.md#list-of-contents) 69 | -------------------------------------------------------------------------------- /basics/installing-python.md: -------------------------------------------------------------------------------- 1 | # Installing Python 2 | 3 | If you want to learn to program with Python using this tutorial, you 4 | need to try out the code examples. You can use a website like 5 | [repl.it](https://repl.it/languages/python3), but I highly recommend 6 | installing Python. That way you don't need to open a web browser just 7 | to write code, and you can work without an Internet connection. 8 | 9 | It doesn't matter which operating system you use because Python runs 10 | great on Windows, Mac OSX, Linux and many other operating systems. 11 | However, installing and launching Python are done differently on 12 | different operating systems, so just follow your operating system's 13 | instructions. 14 | 15 | Let's get started! 16 | 17 | ## Downloading and installing Python 18 | 19 | ### Windows 20 | 21 | Installing Python on Windows is a lot like installing any other program. 22 | 23 | 1. Go to [the official Python website](https://www.python.org/). 24 | 2. Move your mouse over the blue Downloads button, but don't click it. 25 | Then click the button that downloads the latest version of Python. 26 | 3. Run the installer. 27 | 4. Make sure that the launcher gets installed and click Install Now. 28 | 29 | ![The py.exe launcher.](../images/py-exe.png) 30 | 31 | ### Mac OSX 32 | 33 | At the time of writing this, Macs don't come with a Python 3 and you 34 | need to install it yourself. It should be like installing any other 35 | program, but unfortunately I don't have better instructions because I 36 | don't have an up-to-date Mac and I have never installed Python on a Mac. 37 | If you would like to write better instructions, [tell 38 | me](../contact-me.md). 39 | 40 | ### Linux 41 | 42 | You already have Python 3, **there's no need to install anything**. You 43 | may also have Python 2, but don't try to remove it. 44 | Some of the programs that came with your operating system 45 | are probably written in Python 2, so removing Python 2 would 46 | break them. 47 | 48 | ## Running Python 49 | 50 | Next we'll learn to run Python on a PowerShell or terminal. There are 51 | several other ways to run Python, but if you learn this way now it's 52 | going to make things easier later. 53 | 54 | ### Windows 55 | 56 | 1. Open a PowerShell from your start menu or start screen. 57 | 2. Type `py` and press Enter. You should see something like this: 58 | 59 | ![Python running in a PowerShell window.](../images/powershell.png) 60 | 61 | ### Other operating systems 62 | 63 | 1. Open a terminal. How exactly this is done depends on your operating 64 | system, but most operating systems have some way to search for 65 | programs. Search for a program called terminal and launch it. 66 | 2. Type `python3` and press Enter. You should see something like this: 67 | 68 | ![Running Python on my terminal.](../images/terminal.png) 69 | 70 | Your terminal probably looks different than mine, it's OK. 71 | 72 | Now you can type `exit()` and press Enter to get out of Python. Or you 73 | can just close the PowerShell or Terminal window. 74 | 75 | ## Summary 76 | 77 | Now you should have Python installed, and you should be able run it. 78 | 79 | *** 80 | 81 | If you have trouble with this tutorial, please 82 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 83 | or [ask for help online](../getting-help.md). 84 | If you like this tutorial, please [give it a 85 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 86 | 87 | You may use this tutorial freely at your own risk. See 88 | [LICENSE](../LICENSE). 89 | 90 | [Previous](what-is-programming.md) | [Next](getting-started.md) | 91 | [List of contents](../README.md#basics) 92 | -------------------------------------------------------------------------------- /update-readmes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This is free and unencumbered software released into the public 4 | # domain. 5 | 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a 8 | # compiled binary, for any purpose, commercial or non-commercial, and 9 | # by any means. 10 | 11 | # In jurisdictions that recognize copyright laws, the author or 12 | # authors of this software dedicate any and all copyright interest in 13 | # the software to the public domain. We make this dedication for the 14 | # benefit of the public at large and to the detriment of our heirs 15 | # and successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to 17 | # this software under copyright law. 18 | 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 23 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 24 | # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | # For more information, please refer to 28 | 29 | """Generate basics/README.md and advanced/README.md.""" 30 | 31 | import os 32 | import posixpath 33 | 34 | import common 35 | 36 | 37 | BEGINNING = """\ 38 | [comment]: # (This file is automatically generated. Don't edit this) 39 | [comment]: # (file manually, run update-readmes.py instead.) 40 | 41 | """ 42 | 43 | 44 | def get_contents(): 45 | """Read descriptions and contents lists from README. 46 | 47 | Return a {chaptername: content} dictionary. 48 | """ 49 | result = {} 50 | current_section = None 51 | 52 | with open('README.md', 'r') as f: 53 | # move to where the content list starts 54 | while f.readline().strip() != "## List of contents": 55 | pass 56 | 57 | for line in f: 58 | if line.startswith('### '): 59 | # new section 60 | current_section = common.header_link(line.lstrip('#').strip()) 61 | result[current_section] = line[2:] # one # instead of 3 62 | elif line.startswith('## '): 63 | # end of content lists 64 | break 65 | elif current_section is not None: 66 | # we are currently in a section 67 | result[current_section] += line 68 | 69 | return result 70 | 71 | 72 | def update_file(filename, content): 73 | """Make sure that a file contains the content. 74 | 75 | Return True if the file changed and False if it didn't. 76 | """ 77 | try: 78 | with open(filename, 'r') as f: 79 | # ignore the end 80 | old_content = f.read().split('\n***\n')[0].rstrip() 81 | if old_content == content: 82 | print("Has correct content:", filename) 83 | return False 84 | except FileNotFoundError: 85 | # the file doesn't exist yet, we'll create it 86 | pass 87 | 88 | print("Writing new content:", filename) 89 | with open(filename, 'w') as f: 90 | print(content, file=f) 91 | return True 92 | 93 | 94 | def main(): 95 | something_changed = False 96 | for directory, content in sorted(get_contents().items()): 97 | if not os.path.exists(directory): 98 | # something else under the list of contents than a chapter 99 | # list, doesn't have a separate subdirectory 100 | print("Not a directory:", directory) 101 | continue 102 | 103 | # the links that point to the subdir must now point to the 104 | # current directory, so we fix that 105 | content = BEGINNING + content.replace(directory + '/', '').rstrip() 106 | path = os.path.join(directory, 'README.md') 107 | this_changed = update_file(path, content) 108 | something_changed = something_changed or this_changed 109 | 110 | if something_changed: 111 | print() 112 | print("Run update-ends.py now so the files will have correct ends.") 113 | 114 | 115 | if __name__ == '__main__': 116 | main() 117 | -------------------------------------------------------------------------------- /basics/editor-setup.md: -------------------------------------------------------------------------------- 1 | # Setting up an editor for programming 2 | 3 | An editor is a program that lets us write longer programs than we can 4 | write on the `>>>` prompt. With an editor we can save the programs to files and 5 | run them as many times as we want without writing them again. 6 | 7 | When programmers say "editor" they don't mean programs like Microsoft 8 | Word or LibreOffice/OpenOffice Writer. These programs are for writing 9 | text documents, not for programming. **Programming editors don't support 10 | things like bigger font sizes for titles or underlining bits of text**, 11 | but instead they have features that are actually useful for programming, 12 | like automatically displaying different things with different colors, 13 | but also highlighting mistakes in the code, and coloring syntax. 14 | 15 | If you are on Windows or Mac OSX you have probably noticed that your 16 | Python came with an editor called IDLE. You can use IDLE, but we recommend exploring other options first. 17 | 18 | 19 | ## Which editor? 20 | 21 | The choice of an editor is a very personal thing. There are many 22 | editors, and most programmers have a favorite editor that they use for 23 | everything and recommend to everyone. 24 | 25 | The editors can be broadly divided into three categories: 26 | 27 | #### The Basic Text Editors 28 | These editors usually come with the operating system. They do not have features like 29 | running code, auto-completion, etc. that make programming easier. They are usually used for relatively simple 30 | text editing. Most programmers do not use these editors for programming. 31 | 32 | A few popular ones in this category are: 33 | - Notepad (Windows) 34 | - Gedit (Linux) 35 | - Notepad ++ (Windows) 36 | - Nano (Linux/Mac OS) 37 | 38 | #### Smart Text Editors 39 | The text editors in this category have features like auto-completion, syntax highlighting, 40 | running and debugging code, highlighting errors, etc. They are relatively easy to learn and have the necessary features 41 | to start your programming journey. 42 | 43 | A few popular ones in this category are: 44 | - Visual Studio Code / VS Code (Windows/Linux/Mac OS) 45 | - IDLE (Usually comes with Python) (Windows/Linux/Mac OS) 46 | - Thonny (Windows/Linux/Mac OS) 47 | - [Porcupine](https://github.com/Akuli/porcupine) (created by the author of this tutorial) (Windows/Linux/Mac OS) 48 | - Geany (Windows/Linux/Mac OS) 49 | 50 | **We recommend that you look into a few of these editors and install your favorite one.** 51 | 52 | #### IDEs and advanced editors 53 | This category of text editors are usually professional grade pieces of software. They are mostly proprietary and paid. They have a steep 54 | learning curve because of how many features they have. 55 | These types of editors are generally not preferred 56 | in the beginning stage. They are meant to be used for writing complex and large pieces of software. 57 | 58 | A few popular ones in this category are: 59 | - Visual Studio (Not be confused with *Visual Studio Code*) (Windows) 60 | - Pycharm (Windows/Linux/Mac OS) 61 | - Vim (Windows/Linux/Mac OS) 62 | - Emacs (Windows/Linux/Mac OS) 63 | 64 | As already mentioned, there are no "right" or "wrong" editors. The preference of an editor 65 | is a personal choice and we recommend trying different editors. 66 | The lists on this page don't contain all editors, but just a few of the most popular ones. 67 | 68 | ## Editor or `>>>` prompt? 69 | 70 | So far we have used the `>>>` prompt for everything. But now we also 71 | have an editor that lets us write longer programs. So why not just 72 | always use the editor? 73 | 74 | The `>>>` prompt is meant to be used for experimenting with things. For 75 | example, if you want to know what `"hello" + 123` does, just open the 76 | prompt and run it. 77 | 78 | If you want to write something once and then run it many times, write 79 | the code to a file. For example, if you want to make a program that asks 80 | the user to enter a word and then echoes it back, write a program that 81 | does that in a file and run it as many times as you want to. 82 | 83 | Note that if you write something like `'hello'` to the `>>>` prompt it 84 | echoes it back, but if you make a file that contains nothing but a 85 | `'hello'` it won't do anything when you run it. You need to use 86 | `print('hello')` instead when your code is in a file. 87 | 88 | *** 89 | 90 | If you have trouble with this tutorial, please 91 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 92 | or [ask for help online](../getting-help.md). 93 | If you like this tutorial, please [give it a 94 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 95 | 96 | You may use this tutorial freely at your own risk. See 97 | [LICENSE](../LICENSE). 98 | 99 | [Previous](using-functions.md) | [Next](if.md) | 100 | [List of contents](../README.md#basics) 101 | -------------------------------------------------------------------------------- /update-ends.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This is free and unencumbered software released into the public 4 | # domain. 5 | 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a 8 | # compiled binary, for any purpose, commercial or non-commercial, and 9 | # by any means. 10 | 11 | # In jurisdictions that recognize copyright laws, the author or 12 | # authors of this software dedicate any and all copyright interest in 13 | # the software to the public domain. We make this dedication for the 14 | # benefit of the public at large and to the detriment of our heirs 15 | # and successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to 17 | # this software under copyright law. 18 | 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 23 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 24 | # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | # For more information, please refer to 28 | 29 | """Update ends of markdown files.""" 30 | 31 | import posixpath 32 | import re 33 | 34 | import common 35 | 36 | 37 | END_TEMPLATE = """\ 38 | If you have trouble with this tutorial, please 39 | [tell me about it]({toplevel}/contact-me.md) and I'll make this tutorial better, 40 | or [ask for help online]({toplevel}/getting-help.md). 41 | If you like this tutorial, please [give it a 42 | star]({toplevel}/README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 43 | 44 | You may use this tutorial freely at your own risk. See 45 | [LICENSE]({toplevel}/LICENSE). 46 | 47 | {extralinks}[List of contents]({toplevel}/README.md#{readmeheader}) 48 | """ 49 | 50 | CHAPTER_LINK_REGEX = r'^\d+\. \[.*\]\((.*\.md)\)$' 51 | 52 | 53 | def get_filenames(): 54 | """Get chapter files and other files from README. 55 | 56 | Return a two-tuple of chapter file names and other file names as 57 | iterables of strings. 58 | """ 59 | chapters = [] 60 | with open('README.md', 'r') as f: 61 | # move to where the content list starts 62 | while f.readline().strip() != "## List of contents": 63 | pass 64 | 65 | # now let's read the content list 66 | for line in f: 67 | line = line.strip() 68 | if line.startswith('## '): 69 | # end of content list 70 | break 71 | if line: 72 | # not empty line 73 | match = re.search(CHAPTER_LINK_REGEX, line) 74 | if match is not None: 75 | # it's a link to a chapter 76 | chapters.append(match.group(1)) 77 | 78 | others = set(common.get_markdown_files()) - set(chapters) 79 | return chapters, others 80 | 81 | 82 | def update_end(filename, end): 83 | """Add *** and end to a file if it doesn't have them already. 84 | 85 | filename should be relative to the toplevel using / as a path 86 | separator. 87 | """ 88 | end = '\n***\n\n' + end 89 | with open(filename, 'r') as f: 90 | content = f.read() 91 | if content.endswith(end): 92 | # No need to do anything. 93 | print(" Has correct end:", filename) 94 | return 95 | 96 | if '\n***\n' in content: 97 | # We need to remove the old ending first. 98 | print(" Removing old end:", filename) 99 | where = content.index('\n***\n') 100 | with open(filename, 'w') as f: 101 | f.write(content[:where]) 102 | 103 | print(" Adding end:", filename) 104 | with open(filename, 'a') as f: 105 | f.write(end) 106 | 107 | 108 | def main(): 109 | chapter_files, other_files = get_filenames() 110 | 111 | # make previous of first file and next of last file to just bring 112 | # back to README 113 | prevs = ['README.md'] + chapter_files[:-1] 114 | nexts = chapter_files[1:] + ['README.md'] 115 | 116 | print("Chapter files:") 117 | for prevpath, thispath, nextpath in zip(prevs, chapter_files, nexts): 118 | # all paths should be like 'section/file.md' 119 | where = posixpath.dirname(thispath) 120 | prev = posixpath.relpath(prevpath, where) 121 | next_ = posixpath.relpath(nextpath, where) 122 | extralinks = "[Previous](%s) | [Next](%s) |\n" % (prev, next_) 123 | end = END_TEMPLATE.format( 124 | toplevel='..', extralinks=extralinks, readmeheader=where) 125 | update_end(thispath, end) 126 | 127 | print() 128 | 129 | print("Other files:") 130 | for filename in other_files: 131 | where = posixpath.dirname(filename) 132 | end = END_TEMPLATE.format( 133 | toplevel=posixpath.relpath('.', where), 134 | extralinks="", readmeheader='list-of-contents') 135 | update_end(filename, end) 136 | 137 | 138 | if __name__ == '__main__': 139 | main() 140 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python programming tutorial for beginners 2 | 3 | This is a concise Python 3 programming tutorial for people who think 4 | that reading is boring. I try to show everything with simple code 5 | examples; there are no long and complicated explanations with fancy 6 | words. If you have never programmed before click 7 | [here](basics/what-is-programming.md) to find out what programming is 8 | like and get started. 9 | 10 | This tutorial is aimed at people with no programming experience at all 11 | or very little programming experience. If you have programmed a lot in 12 | the past using some other language you may want to read [the official 13 | tutorial](https://docs.python.org/3/tutorial/) instead. 14 | 15 | You can use Python 3.6 or any newer Python with this tutorial. **Don't 16 | use Python 2 because it's no longer supported.** 17 | 18 | ## List of contents 19 | 20 | The tutorial consists of two sections: 21 | 22 | ### Basics 23 | 24 | This section will get you started with using Python and you'll be able 25 | to learn more about whatever you want after studying it. 26 | 27 | 1. [What is programming?](basics/what-is-programming.md) 28 | 2. [Installing Python](basics/installing-python.md) 29 | 3. [Getting started with Python](basics/getting-started.md) 30 | 4. [ThinkPython: The way of the program](basics/the-way-of-the-program.md) 31 | 5. [Variables, Booleans and None](basics/variables.md) 32 | 6. [Using functions](basics/using-functions.md) 33 | 7. [Setting up an editor](basics/editor-setup.md) 34 | 8. [If, else and elif](basics/if.md) 35 | 9. [Handy stuff with strings](basics/handy-stuff-strings.md) 36 | 10. [Lists and tuples](basics/lists-and-tuples.md) 37 | 11. [Loops](basics/loops.md) 38 | 12. [zip and enumerate](basics/zip-and-enumerate.md) 39 | 13. [Dictionaries](basics/dicts.md) 40 | 14. [Defining functions](basics/defining-functions.md) 41 | 15. [Writing a larger program](basics/larger-program.md) 42 | 16. [What is true?](basics/what-is-true.md) 43 | 17. [Files](basics/files.md) 44 | 18. [Modules](basics/modules.md) 45 | 19. [Exceptions](basics/exceptions.md) 46 | 20. [Classes](basics/classes.md) 47 | 21. [Docstrings](basics/docstrings.md) 48 | 49 | ### Advanced 50 | 51 | If you want to learn more advanced techniques, you can also read this 52 | section. Most of the techniques explained here are great when you're 53 | working on a large project, and your code would be really repetitive 54 | without these things. 55 | 56 | You can experiment with these things freely, but please **don't use these 57 | techniques just because you know how to use them.** Prefer the simple 58 | techniques from the Basics part instead when possible. Simple is better 59 | than complex. 60 | 61 | 1. [Handy data types](advanced/datatypes.md) 62 | 2. [Advanced stuff with functions](advanced/functions.md) 63 | 3. [Magic methods](advanced/magicmethods.md) 64 | 4. [Iterables, iterators and generators](advanced/iters.md) 65 | 66 | ### Other things this tutorial comes with 67 | 68 | - **Important:** [getting help](getting-help.md) 69 | - [Contact me](contact-me.md) 70 | - Answers for exercises in [basics](basics/answers.md) and 71 | [advanced](advanced/answers.md) sections 72 | - [The TODO list](TODO.md) 73 | 74 | ## Frequently asked questions 75 | 76 | ### How can I thank you for writing and sharing this tutorial? 77 | 78 | You can star this tutorial. Starring is free for you, but it tells me 79 | and other people that you like this tutorial. 80 | 81 | Go [here](https://github.com/Akuli/python-tutorial) if you aren't here 82 | already and click the "Star" button in the top right corner. You will be 83 | asked to create a GitHub account if you don't already have one. 84 | 85 | ### How can I read this tutorial without an Internet connection? 86 | 87 | 1. Go [here](https://github.com/Akuli/python-tutorial) if you aren't 88 | here already. 89 | 2. Click the big green "Clone or download" button in the top right of 90 | the page, then click "Download ZIP". 91 | 92 | ![Download ZIP](images/download-me.png) 93 | 94 | 3. Extract the ZIP and open it. Unfortunately I don't have any more 95 | specific instructions because how exactly this is done depends on 96 | which operating system you run. 97 | 4. Run `make-html.py` and follow the instructions. 98 | 99 | If you have git and you know how to use it, you can also clone the 100 | repository instead of downloading a zip and extracting it. An advantage 101 | with doing it this way is that you don't need to download the whole 102 | tutorial again to get the latest version of it, all you need to do is to 103 | pull with git and run `make-html.py` again. 104 | 105 | ## Authors 106 | 107 | I'm Akuli and I have written most of this tutorial, but other people have helped me with it. 108 | See [github's contributors page](https://github.com/Akuli/python-tutorial/graphs/contributors) for details. 109 | 110 | *** 111 | 112 | If you have trouble with this tutorial, please 113 | [tell me about it](./contact-me.md) and I'll make this tutorial better, 114 | or [ask for help online](./getting-help.md). 115 | If you like this tutorial, please [give it a 116 | star](./README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 117 | 118 | You may use this tutorial freely at your own risk. See 119 | [LICENSE](./LICENSE). 120 | 121 | [List of contents](./README.md#list-of-contents) 122 | -------------------------------------------------------------------------------- /linkcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This is free and unencumbered software released into the public 4 | # domain. 5 | 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a 8 | # compiled binary, for any purpose, commercial or non-commercial, and 9 | # by any means. 10 | 11 | # In jurisdictions that recognize copyright laws, the author or 12 | # authors of this software dedicate any and all copyright interest in 13 | # the software to the public domain. We make this dedication for the 14 | # benefit of the public at large and to the detriment of our heirs 15 | # and successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to 17 | # this software under copyright law. 18 | 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 23 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 24 | # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | # For more information, please refer to 28 | 29 | """Check for broken links. 30 | 31 | This finds links like this... 32 | 33 | [click here](some-file.md) 34 | [or here](../some/path/another-file.md) 35 | ![here's an image](../images/some-cool-image.png) 36 | 37 | ...but not like this: 38 | 39 | [some website](http://github.com/) 40 | [another website](https://github.com/) 41 | [local link](#some-title) 42 | """ 43 | 44 | import os 45 | import posixpath 46 | 47 | import common 48 | 49 | 50 | def check(this_file, target, title, titledict): 51 | """Check if a link's target is like it should be. 52 | 53 | Return an error message string or "ok". 54 | """ 55 | if target.startswith(('http://', 'https://')): 56 | # We don't need this currently, but checking these links could 57 | # be added later. 58 | return "ok" 59 | 60 | path = posixpath.join(posixpath.dirname(this_file), target) 61 | path = posixpath.normpath(path) 62 | 63 | if not os.path.exists(path): 64 | return "doesn't exist" 65 | 66 | if target.endswith('/'): 67 | # A directory. 68 | if not os.path.isdir(path): 69 | return "not a directory" 70 | else: 71 | # A file. 72 | if not os.path.isfile(path): 73 | return "not a file" 74 | 75 | if title is not None and title not in titledict[path]: 76 | return "no title named %s" % title 77 | return "ok" 78 | 79 | 80 | def find_titles(filename): 81 | """Read titles of a markdown file and return a list of them.""" 82 | result = [] 83 | 84 | with open(filename, 'r') as f: 85 | for line in f: 86 | if line.startswith('```'): 87 | # it's a code block, let's skip to the end of it to 88 | # avoid detecting comments as titles 89 | while f.readline().rstrip() != '```': 90 | pass 91 | if line.startswith('#'): 92 | # found a title 93 | result.append(common.header_link(line.lstrip('#').strip())) 94 | 95 | return result 96 | 97 | 98 | def find_links(this_file): 99 | """Read links of a markdown file. 100 | 101 | Return a list of (target, title, lineno) pairs where title can be None. 102 | """ 103 | result = [] 104 | 105 | with open(this_file, 'r') as f: 106 | for match, lineno in common.find_links(f): 107 | target = match.group(2) 108 | if '#' in target: 109 | file, title = target.split('#', 1) 110 | if not file: 111 | # link to this file, [blabla](#hi) 112 | file = posixpath.basename(this_file) 113 | else: 114 | file = target 115 | title = None 116 | 117 | result.append((file, title, lineno)) 118 | 119 | return result 120 | 121 | 122 | def get_line(filename, lineno): 123 | """Return the lineno'th line of a file.""" 124 | with open(filename, 'r') as f: 125 | for lineno2, line in enumerate(f, start=1): 126 | if lineno == lineno2: 127 | return line 128 | raise ValueError("%s is less than %d lines long" % (filename, lineno)) 129 | 130 | 131 | def main(): 132 | print("Searching for titles and links...") 133 | titledict = {} # {filename: [title1, title2, ...]} 134 | linkdict = {} # {filename: [(file, title, lineno), ...]) 135 | for path in common.get_markdown_files(): 136 | titledict[path] = find_titles(path) 137 | linkdict[path] = find_links(path) 138 | 139 | print("Checking the links...") 140 | total = 0 141 | broken = 0 142 | 143 | for filename, linklist in linkdict.items(): 144 | for target, title, lineno in linklist: 145 | status = check(filename, target, title, titledict) 146 | if status != "ok": 147 | print(" file %s, line %d: %s" % (filename, lineno, status)) 148 | print(" %s" % get_line(filename, lineno)) 149 | broken += 1 150 | total += 1 151 | 152 | print("%d/%d links seem to be broken." % (broken, total)) 153 | 154 | 155 | if __name__ == '__main__': 156 | main() 157 | -------------------------------------------------------------------------------- /common.py: -------------------------------------------------------------------------------- 1 | # This is free and unencumbered software released into the public 2 | # domain. 3 | 4 | # Anyone is free to copy, modify, publish, use, compile, sell, or 5 | # distribute this software, either in source code form or as a 6 | # compiled binary, for any purpose, commercial or non-commercial, and 7 | # by any means. 8 | 9 | # In jurisdictions that recognize copyright laws, the author or 10 | # authors of this software dedicate any and all copyright interest in 11 | # the software to the public domain. We make this dedication for the 12 | # benefit of the public at large and to the detriment of our heirs 13 | # and successors. We intend this dedication to be an overt act of 14 | # relinquishment in perpetuity of all present and future rights to 15 | # this software under copyright law. 16 | 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 21 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 22 | # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | # For more information, please refer to 26 | 27 | """Things that other scripts import and use. 28 | 29 | The markdown files use / as a path separator. That's why they need the 30 | posixpath module for processing paths, but they use functions in this 31 | file when actually opening files. 32 | """ 33 | 34 | import contextlib 35 | import itertools 36 | import os 37 | import posixpath 38 | import re 39 | import shutil 40 | import string 41 | 42 | 43 | _LINK_REGEX = r'!?\[(.*?)\]\((.*?)\)' 44 | 45 | 46 | def find_links(file): 47 | """Find all markdown links in a file object. 48 | 49 | Yield (lineno, regexmatch) tuples. 50 | """ 51 | # don't yield same link twice 52 | seen = set() 53 | 54 | # we need to loop over the file two lines at a time to support 55 | # multi-line (actually two-line) links, so this is kind of a mess 56 | firsts, seconds = itertools.tee(file) 57 | next(seconds) # first line is never second line 58 | 59 | # we want 1-based indexing instead of 0-based and one-line links get 60 | # caught from linepair[1], so we need to start at two 61 | for lineno, linepair in enumerate(zip(firsts, seconds), start=2): 62 | lines = linepair[0] + linepair[1] 63 | for match in re.finditer(_LINK_REGEX, lines, flags=re.DOTALL): 64 | if match.group(0) not in seen: 65 | seen.add(match.group(0)) 66 | yield match, lineno 67 | 68 | 69 | def get_markdown_files(): 70 | """Yield the names of all markdown files in this tutorial. 71 | 72 | The yielded paths use / as the path separator. 73 | """ 74 | for root, dirs, files in os.walk('.'): 75 | for file in files: 76 | if not file.endswith('.md'): 77 | continue 78 | path = os.path.normpath(os.path.join(root, file)) 79 | yield path.replace(os.sep, '/') 80 | 81 | 82 | def header_link(title): 83 | """Return a github-style link target for a title. 84 | 85 | >>> header_link('Hello there!') 86 | 'hello-there' 87 | """ 88 | # This doesn't do the-title-1, the-title-2 etc. with multiple titles 89 | # with same text, but usually this doesn't matter. 90 | result = '' 91 | for character in title: 92 | if character in string.whitespace: 93 | result += '-' 94 | elif character in string.punctuation: 95 | pass 96 | else: 97 | result += character.lower() 98 | return result 99 | 100 | 101 | def askyesno(question, default=True): 102 | """Ask a yes/no question and return True or False. 103 | 104 | The default answer is yes if default is True and no if default is 105 | False. 106 | """ 107 | if default: 108 | # yes by default 109 | question += ' [Y/n] ' 110 | else: 111 | # no by default 112 | question += ' [y/N] ' 113 | 114 | while True: 115 | result = input(question).upper().strip() 116 | if result == 'Y': 117 | return True 118 | if result == 'N': 119 | return False 120 | if not result: 121 | return default 122 | print("Please type y, n or nothing at all.") 123 | 124 | 125 | @contextlib.contextmanager 126 | def backup(filename): 127 | """A context manager that backs up a file.""" 128 | shutil.copy(filename, filename + '.backup') 129 | try: 130 | yield 131 | except Exception: 132 | # It failed, we need to restore from the backup. 133 | shutil.copy(filename + '.backup', filename) 134 | else: 135 | # Everything's fine, we can safely get rid of the backup. 136 | os.remove(filename + '.backup') 137 | 138 | 139 | def header_link(title): 140 | """Return a github-style link target for a title. 141 | 142 | >>> header_link('Hello there!') 143 | 'hello-there' 144 | """ 145 | # This doesn't handle multiple titles with the same text in the 146 | # same file, but usually that's not a problem. GitHub makes 147 | # links like the-title, the-title-1, the-title-2 etc. 148 | result = '' 149 | for character in title: 150 | if character in string.whitespace: 151 | result += '-' 152 | elif character in string.punctuation: 153 | pass 154 | else: 155 | result += character.lower() 156 | return result 157 | -------------------------------------------------------------------------------- /basics/what-is-true.md: -------------------------------------------------------------------------------- 1 | # What is true? 2 | 3 | Now we understand how code like this works. 4 | 5 | ```python 6 | message = input("Enter something: ") 7 | if message == '': 8 | print("You didn't enter anything!") 9 | else: 10 | print("You entered:", message) 11 | ``` 12 | 13 | But most Python programmers would write that code like this 14 | instead: 15 | 16 | ```python 17 | message = input("Enter something: ") 18 | if message: 19 | print("You entered:", message) 20 | else: 21 | print("You didn't enter anything!") 22 | ``` 23 | 24 | What the heck was that? We did `if message`, but `message` 25 | was a string, not True or False! 26 | 27 | Python converted our message to a Boolean and then checked if 28 | the Boolean it ended up with was True. But when will it be true? 29 | 30 | ## Converting to Booleans 31 | 32 | The `if message:` actually did the same thing as `if bool(message)`, 33 | which is same as `if bool(message) == True:`. Usually we just don't 34 | write the `==True` part anywhere because we don't need it. 35 | 36 | We can convert things to Booleans like Python did by doing 37 | `bool(things)`. Let's try that with strings. 38 | 39 | ```python 40 | >>> bool('hello') 41 | True 42 | >>> bool('there') 43 | True 44 | >>> bool('True') 45 | True 46 | >>> bool('False') # this isn't special in any way 47 | True 48 | >>> 49 | ``` 50 | 51 | As we can see, the Boolean value of most strings is True. The 52 | only string that has a false Boolean value is the empty string, 53 | `''` or `""`: 54 | 55 | ```python 56 | >>> bool('') 57 | False 58 | >>> 59 | ``` 60 | 61 | Most other things are also treated as False if they're empty and 62 | True if they're not empty. 63 | 64 | ```python 65 | >>> bool([1, 2, 3]) 66 | True 67 | >>> bool([]) 68 | False 69 | >>> bool((1, 2, 3)) 70 | True 71 | >>> bool(()) 72 | False 73 | >>> bool({'a': 1, 'b': 2}) 74 | True 75 | >>> bool({}) 76 | False 77 | >>> 78 | ``` 79 | 80 | None and zero are also falsy, but positive and negative numbers 81 | are treated as True. 82 | 83 | ```python 84 | >>> bool(None) 85 | False 86 | >>> bool(0) 87 | False 88 | >>> bool(0.0) 89 | False 90 | >>> bool(1) 91 | True 92 | >>> bool(-1) 93 | True 94 | >>> 95 | ``` 96 | 97 | Most other things are also treated as True. 98 | 99 | ```python 100 | >>> bool(OSError) 101 | True 102 | >>> bool(print) 103 | True 104 | >>> 105 | ``` 106 | 107 | ## When and why should we use Boolean values of things? 108 | 109 | It's recommended to rely on the Boolean value when we're doing 110 | something with things like lists and tuples. This way our code 111 | will work even if it gets a value of a different type than we 112 | expected it to get originally. 113 | 114 | For example, this code doesn't work right if we give it 115 | something else than a list. It thinks that empty tuples, 116 | strings and dictionaries aren't empty just because they aren't 117 | empty lists: 118 | 119 | ```python 120 | >>> def is_this_empty(thing): 121 | ... if thing == []: 122 | ... print("It's empty!") 123 | ... else: 124 | ... print("It's not empty.") 125 | ... 126 | >>> is_this_empty([1, 2, 3]) 127 | It's not empty. 128 | >>> is_this_empty([]) 129 | It's empty! 130 | >>> is_this_empty(()) 131 | It's not empty. 132 | >>> is_this_empty('') 133 | It's not empty. 134 | >>> is_this_empty({}) 135 | It's not empty. 136 | >>> 137 | ``` 138 | 139 | We could improve the code by checking against different empty 140 | things. 141 | 142 | ```python 143 | >>> def is_this_empty(thing): 144 | ... if thing == [] or thing == () or thing == '' or thing == {}: 145 | ... print("It's empty!") 146 | ... else: 147 | ... print("It's not empty.") 148 | ... 149 | >>> 150 | ``` 151 | 152 | But Python has many other data types that can be empty and we 153 | haven't talked about in this tutorial. Trying to check all of 154 | them would be pointless because functions like this already 155 | work with all of them: 156 | 157 | ```python 158 | >>> def is_this_empty(thing): 159 | ... if thing: 160 | ... print("It's not empty.") 161 | ... else: 162 | ... print("It's empty!") 163 | ... 164 | >>> 165 | ``` 166 | 167 | There's also cases when we should not rely on the Boolean value. 168 | When we're doing things with numbers and None it's best to 169 | simply compare to None or zero. Like this: 170 | 171 | ```python 172 | if number != 0: 173 | print("number is not zero") 174 | 175 | if value is not None: 176 | print("value is not None") 177 | ``` 178 | 179 | Not like this: 180 | 181 | ```python 182 | if number: 183 | print("number is not zero") 184 | 185 | if value: 186 | print("value is not None") 187 | ``` 188 | 189 | We used `is not` instead of `!=` in the first example because 190 | the official style guide recommends it. The reason is that it's 191 | possible to create a value that isn't really None but seems like 192 | None when we compare it with None using `==` or `!=`, and we want 193 | to make sure that we don't treat values like that as None. 194 | 195 | So here's how we should check if something is None: 196 | 197 | ```python 198 | if not value: ... # not good if we want to check if it's None 199 | if value == None: ... # better 200 | if value is None: ... # best 201 | ``` 202 | 203 | ## Summary 204 | 205 | - `if thing:` does the same thing as `if bool(thing):`. This also 206 | works with while loops and most other things that are usually used 207 | with Booleans. 208 | - `bool()` of most things is True, but `bool()` values of None, 209 | zero and most empty things are False. 210 | - Use `is` and `is not` when comparing to None, `==` and `!=` when 211 | checking if a number is zero and rely on the Boolean value 212 | when checking if something is empty. 213 | 214 | *** 215 | 216 | If you have trouble with this tutorial, please 217 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 218 | or [ask for help online](../getting-help.md). 219 | If you like this tutorial, please [give it a 220 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 221 | 222 | You may use this tutorial freely at your own risk. See 223 | [LICENSE](../LICENSE). 224 | 225 | [Previous](larger-program.md) | [Next](files.md) | 226 | [List of contents](../README.md#basics) 227 | -------------------------------------------------------------------------------- /basics/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting started with Python 2 | 3 | [Launch Python](installing-python.md). 4 | 5 | The `>>>` means that Python is ready and we can enter a command. The 6 | basic idea is really simple: we enter a command, press Enter, enter 7 | another command, press Enter and keep going. 8 | 9 | You probably don't know any Python commands yet. Let's see what happens 10 | if we just write something and press Enter. 11 | 12 | ```python 13 | >>> hello 14 | Traceback (most recent call last): 15 | File "", line 1, in 16 | NameError: name 'hello' is not defined 17 | >>> 18 | ``` 19 | 20 | Oops! That didn't work. But like I wrote in the 21 | [introduction](what-is-programming.md), error messages are our friends. 22 | This error message tells us what's wrong and where, and we'll learn what 23 | "name 'hello' is not defined" means [later](variables.md). 24 | 25 | Maybe we can press Enter without typing anything? 26 | 27 | ```python 28 | >>> 29 | >>> 30 | >>> 31 | >>> 32 | ``` 33 | 34 | That worked. How about numbers? 35 | 36 | ```python 37 | >>> 123 38 | 123 39 | >>> -123 40 | -123 41 | >>> 3.14 42 | 3.14 43 | >>> -12.3 44 | -12.3 45 | >>> 46 | ``` 47 | 48 | There we go, it echoes them back. 49 | 50 | In some countries, decimal numbers are written with a comma, like `3,14` 51 | instead of `3.14`. Maybe Python knows that? 52 | 53 | ```python 54 | >>> 3,14 55 | (3, 14) 56 | >>> 57 | ``` 58 | 59 | We didn't get an error... but `(3, 14)` is not at all what we expected! 60 | So from now on, let's use a dot with decimal numbers, because `3.14` 61 | worked just fine. Later we'll learn what `(3, 14)` is. 62 | 63 | ## Comments 64 | 65 | **Comments are text that don't do anything when they're run.** 66 | They can be created by typing a `#` and then some text after it, 67 | and they are useful when our code would be hard to understand without them. 68 | 69 | ```python 70 | >>> 1 + 2 # can you guess what the result is? 71 | 3 72 | >>> 73 | ``` 74 | 75 | Again, I put a space after the `#` and multiple spaces before it just to 76 | make things easier to read. 77 | 78 | If we write a comment on a line with no code on it, the prompt changes 79 | from `>>>` to `...`. To be honest, I have no idea why it does that and I 80 | think it would be better if it would just stay as `>>>`. The prompt goes 81 | back to `>>>` when we press Enter again. 82 | 83 | ```python 84 | >>> # hello there 85 | ... 86 | >>> 87 | ``` 88 | 89 | ## Strings 90 | 91 | Strings are small pieces of text that we can use in our programs. We can 92 | create strings by simply writing some text in quotes. 93 | 94 | ```python 95 | >>> 'hello' 96 | 'hello' 97 | >>> 'this is a test' 98 | 'this is a test' 99 | >>> 100 | ``` 101 | 102 | Strings can also be written with "double quotes" instead of 'single 103 | quotes'. This is useful when we need to put quotes inside the string. 104 | 105 | ```python 106 | >>> "hello there" 107 | 'hello there' 108 | >>> "it's sunny" 109 | "it's sunny" 110 | >>> 111 | ``` 112 | 113 | It's also possible to add single quotes and double quotes into the same 114 | string, but most of the time we don't need to do that so I'm not going 115 | to talk about it now. 116 | 117 | It doesn't matter which quotes you use when the string doesn't need to 118 | contain any quotes. If you think that one of the quote types looks nicer 119 | than the other or you find it faster to type, go ahead and use that. 120 | 121 | Strings can be joined together easily with `+` or repeated with `*`: 122 | 123 | ```python 124 | >>> "hello" + "world" 125 | 'helloworld' 126 | >>> "hello" * 3 127 | 'hellohellohello' 128 | >>> 129 | ``` 130 | 131 | Note that a `#` inside a string doesn't create a comment. 132 | 133 | ```python 134 | >>> "strings can contain # characters" 135 | 'strings can contain # characters' 136 | >>> 137 | ``` 138 | 139 | ## Using Python as a calculator 140 | 141 | ```diff 142 | ---------- WARNING: This part contains boring math. Proceed with caution. ---------- 143 | ``` 144 | 145 | Let's type some math stuff into Python and see what it does. 146 | 147 | ```python 148 | >>> 17 + 3 149 | 20 150 | >>> 17 - 3 151 | 14 152 | >>> 17 * 3 153 | 51 154 | >>> 17 / 3 155 | 5.666666666666667 156 | >>> 157 | ``` 158 | 159 | It's working, Python just calculates the result and echoes it back. 160 | 161 | I added a space on both sides of `+`, `-`, `*` and `/`. Everything would 162 | work without those spaces too: 163 | 164 | ```python 165 | >>> 4 + 2 + 1 166 | 7 167 | >>> 4+2+1 168 | 7 169 | >>> 170 | ``` 171 | 172 | However, I recommend always adding the spaces because they make the code 173 | easier to read. 174 | 175 | Things are calculated in the same order as in math. The parentheses `(` 176 | and `)` also work the same way. 177 | 178 | ```python 179 | >>> 1 + 2 * 3 # 2 * 3 is calculated first 180 | 7 181 | >>> (1 + 2) * 3 # 1 + 2 is calculated first 182 | 9 183 | >>> 184 | ``` 185 | 186 | You can also leave out spaces to show what's calculated first. Python 187 | ignores it, but our code will be easier to read for people. 188 | 189 | ```python 190 | >>> 1 + 2*3 # now it looks like 2*3 is calculated first 191 | 7 192 | >>> 193 | ``` 194 | 195 | Python also supports many other kinds of calculations, but most of the 196 | time you don't need them. Actually you don't need even these 197 | calculations most of the time, but these calculations are probably 198 | enough when you need to calculate something. 199 | 200 | ## Summary 201 | 202 | [comment]: # (the first line in this summary is exactly same as in) 203 | [comment]: # (what-is-programming.md, and it's supposed to be like this) 204 | 205 | - Error messages are our friends. 206 | - We can enter any Python commands to the interactive `>>>` prompt, and 207 | it will echo back the result. 208 | - `+`, `-`, `*` and `/` work in Python just like in math. 209 | - Pieces of text starting with a `#` are comments and pieces of text in 210 | quotes are strings. 211 | - You can use single quotes and double quotes however you want. 212 | 213 | *** 214 | 215 | If you have trouble with this tutorial, please 216 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 217 | or [ask for help online](../getting-help.md). 218 | If you like this tutorial, please [give it a 219 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 220 | 221 | You may use this tutorial freely at your own risk. See 222 | [LICENSE](../LICENSE). 223 | 224 | [Previous](installing-python.md) | [Next](the-way-of-the-program.md) | 225 | [List of contents](../README.md#basics) 226 | -------------------------------------------------------------------------------- /basics/zip-and-enumerate.md: -------------------------------------------------------------------------------- 1 | # zip and enumerate 2 | 3 | Now we know how [for loops](loops.md#for-loops) work in Python. But 4 | for loops aren't limited to printing each item in a list, they can 5 | do a lot more. 6 | 7 | To be able to understand for loop tricks we need to first know 8 | assigning values to multiple variables at once. It works like this: 9 | 10 | ```python 11 | >>> a, b = 1, 2 12 | >>> a 13 | 1 14 | >>> b 15 | 2 16 | >>> 17 | ``` 18 | 19 | We can use `()` and `[]` around these values however we want and 20 | everything will still work the same way. `[]` creates a list, and 21 | `()` creates a tuple. 22 | 23 | ```python 24 | >>> [a, b] = (1, 2) 25 | >>> a 26 | 1 27 | >>> b 28 | 2 29 | >>> 30 | ``` 31 | 32 | We can also have `[]` or `()` on one side but not on the other 33 | side. 34 | 35 | ```python 36 | >>> (a, b) = 1, 2 37 | >>> a 38 | 1 39 | >>> b 40 | 2 41 | >>> 42 | ``` 43 | 44 | Python created a tuple automatically. 45 | 46 | ```python 47 | >>> 1, 2 48 | (1, 2) 49 | >>> 50 | ``` 51 | 52 | If we're for looping over a list with pairs of values in it we 53 | could do this: 54 | 55 | ```python 56 | >>> items = [('a', 1), ('b', 2), ('c', 3)] 57 | >>> for pair in items: 58 | ... a, b = pair 59 | ... print(a, b) 60 | ... 61 | a 1 62 | b 2 63 | c 3 64 | >>> 65 | ``` 66 | 67 | Or we can tell the for loop to unpack it for us. 68 | 69 | ```python 70 | >>> for a, b in items: 71 | ... print(a, b) 72 | ... 73 | a 1 74 | b 2 75 | c 3 76 | >>> 77 | ``` 78 | 79 | This feature is often used with Python's built-in `zip()` and `enumerate()` functions. 80 | 81 | 82 | ## zip 83 | 84 | What comes to your mind when you hear the word `zip`? A mechanism extensively used to tie two parts of something, e.g. shirt or jacket. Python's `zip()` functions does pretty much the same, it helps us tie corresponding items together. 85 | 86 | ```python 87 | >>> users = ["Tushar", "Aman", "Anurag", "Sohit"] 88 | >>> uids = ["usr122", "usr123", "usr124", "usr125"] 89 | >>> user_details = zip(uids, users) 90 | >>> print(list(user_details)) 91 | [('usr122', 'Tushar'), ('usr123', 'Aman'), ('usr124', 'Anurag'), ('usr125', 'Sohit')] 92 | >>> 93 | ``` 94 | 95 | Note that `print(user_details)` doesn't work as expected: 96 | 97 | ``` 98 | >>> print(user_details) 99 | 100 | >>> 101 | ``` 102 | 103 | This is because `zip()` is an iterator, i.e. lazy: it gives the items as needed, instead of calculating them and storing them into memory all at once like a list. So the zip object cannot show its elements before the elements are used, because it hasn't computed them yet. 104 | 105 | ```python 106 | >>> users = ["Tushar", "Aman", "Anurag", "Sohit"] 107 | >>> uids = ["usr122", "usr123", "usr124", "usr125"] 108 | >>> user_details = zip(uids, users) 109 | ``` 110 | 111 | If the lists are of different lengths, some items from the end of the longer list will be ignored. 112 | ```python 113 | >>> users = ["Tushar", "Aman", "Anurag"] 114 | >>> emails = ["tushar@example.com", "aman@example.com", "anurag@example.com", "sohit@example.com"] 115 | >>> users_contact = zip(users, emails) 116 | >>> print(list(users_contact)) 117 | [('Tushar', 'tushar@example.com'), ('Aman', 'aman@example.com'), ('Anurag', 'anurag@example.com')] 118 | >>> 119 | ``` 120 | 121 | 122 | Here the shortest list is `users`, with length 3, so `zip(users, emails)` only takes the first 3 emails. 123 | We do not recommend calling `zip()` with lists of different lengths, because ignoring items is usually not what you intended to do. 124 | 125 | ### Using zip in a `for` loop 126 | 127 | It is very common to `for` loop over a `zip()`, and unpack the returned tuples in the `for` loop. 128 | This is why we introduced unpacking in the beginning of this page. 129 | When used this way, there's no need to convert the result of `zip(...)` to a list. 130 | 131 | ```python 132 | >>> roll_nums = [20, 25, 28] 133 | >>> students = ["Joe", "Max", "Michel"] 134 | >>> for roll_num, student in zip(roll_nums, students): 135 | ... print(f"Roll number of {student} is {roll_num}") 136 | ... 137 | Roll number of Joe is 20 138 | Roll number of Max is 25 139 | Roll number of Michel is 28 140 | >>> 141 | ``` 142 | 143 | ## enumerate 144 | 145 | `enumerate()` is an amazing Built-in function offered by python. When used, gives us the index and the item combined. 146 | 147 | ```python 148 | >>> even_nums = [2, 4, 6, 8, 10, 12] 149 | >>> for index, item in enumerate(even_nums): 150 | ... print(f"Index of {item} is {index}") 151 | ... 152 | Index of 2 is 0 153 | Index of 4 is 1 154 | Index of 6 is 2 155 | Index of 8 is 3 156 | Index of 10 is 4 157 | Index of 12 is 5 158 | >>> 159 | ``` 160 | 161 | It is also possible (but more difficult) to do this without `enumerate()`: 162 | 163 | ```python 164 | >>> even_nums = [2, 4, 6, 8, 10, 12] 165 | >>> for index in range(0, len(even_nums)): 166 | ... print(f"Index of {even_nums[index]} is {index}") 167 | ... 168 | Index of 2 is 0 169 | Index of 4 is 1 170 | Index of 6 is 2 171 | Index of 8 is 3 172 | Index of 10 is 4 173 | Index of 12 is 5 174 | >>> 175 | ``` 176 | 177 | Here: 178 | * `range(0, len(even_nums))` gives 0,1,2,3,4,5, with the list length 6 excluded. These are the indexes of our list of length 6. 179 | * `even_nums[index]` prints each element of `even_nums`, because `index` comes from the range of all indexes into that list. 180 | 181 | Because this is complicated to think about and easy to get wrong, it is better to use `enumerate()`. 182 | 183 | ## Exercises 184 | 185 | 1. Create a program that works like this. Here I entered everything 186 | after the `>` prompt that the program displayed. 187 | 188 | ``` 189 | Enter something, and press Enter without typing anything when you're done. 190 | >hello there 191 | >this is a test 192 | >it seems to work 193 | > 194 | Line 1 is: hello there 195 | Line 2 is: this is a test 196 | Line 3 is: it seems to work 197 | ``` 198 | 199 | 2. Create a program that prints all letters from A to Z and a to z 200 | next to each other: 201 | 202 | ``` 203 | A a 204 | B b 205 | C c 206 | ... 207 | X x 208 | Y y 209 | Z z 210 | ``` 211 | 212 | Start your program like this: 213 | 214 | ```python 215 | uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 216 | lowercase = 'abcdefghijklmnopqrstuvwxyz' 217 | ``` 218 | 219 | **Hint:** how do strings behave with `zip`? Try it out on the 220 | `>>>` prompt and see. 221 | 222 | 3. Can you make it print the indexes also? 223 | 224 | ``` 225 | 1 A a 226 | 2 B b 227 | 3 C c 228 | ... 229 | 24 X x 230 | 25 Y y 231 | 26 Z z 232 | ``` 233 | 234 | The answers are [here](answers.md). 235 | 236 | *** 237 | 238 | If you have trouble with this tutorial, please 239 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 240 | or [ask for help online](../getting-help.md). 241 | If you like this tutorial, please [give it a 242 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 243 | 244 | You may use this tutorial freely at your own risk. See 245 | [LICENSE](../LICENSE). 246 | 247 | [Previous](loops.md) | [Next](dicts.md) | 248 | [List of contents](../README.md#basics) 249 | -------------------------------------------------------------------------------- /basics/using-functions.md: -------------------------------------------------------------------------------- 1 | # Using functions 2 | 3 | Now we know how to make Python show text. 4 | 5 | ```python 6 | >>> 'Hello!' 7 | 'Hello!' 8 | >>> 9 | ``` 10 | 11 | But that includes `''`. One way to show text to the user without `''` 12 | is with the print function. In Python, printing doesn't have anything 13 | to do with physical printers, it just means showing text on the screen. 14 | 15 | ```python 16 | >>> print('Hello!') 17 | Hello! 18 | >>> 19 | ``` 20 | 21 | Now we are ready for a classic example, which is also the first program 22 | in many tutorials :) 23 | 24 | ```python 25 | >>> print("Hello World!") 26 | Hello World! 27 | >>> 28 | ``` 29 | 30 | But what exactly is print? 31 | 32 | ## What are functions? 33 | 34 | Let's see what happens if we type `print` without the `('Hello')` part. 35 | 36 | ```python 37 | >>> print 38 | 39 | >>> 40 | ``` 41 | 42 | We could also type `print(print)`, it would do the same thing. Python 43 | replied to us with some information about print wrapped in `<>`. 44 | 45 | As we can see, print is a function. Functions do something when they are 46 | **called** by typing their name and parentheses. Inside the 47 | parentheses, we can pass some arguments too. In `print("hello")` the 48 | function is `print` and we give it one argument, which is `"hello"`. 49 | 50 | Functions are easy to understand, They simply **do something when they 51 | are called**. Functions run immediately when we call them, so the 52 | text appears on the screen right away when we run `print(something)`. 53 | 54 | Sometimes people think that doing `thingy = print('hello')` means that 55 | Python is going to print hello every time we type `thingy`. But **this 56 | is not correct**! `print('hello')` runs print right away, and if we 57 | type `thingy` later it's not going to run `print('hello')` again. 58 | 59 | ## Return values 60 | 61 | Now we know that `thingy = print('hello')` doesn't store the 62 | `print('hello')` call in a variable. But what does it do then? 63 | 64 | ```python 65 | >>> thingy = print('hello') 66 | hello 67 | >>> print(thingy) # thingy is now None 68 | None 69 | >>> 70 | ``` 71 | 72 | So doing `thingy = print('hello')` set `thingy` to None. 73 | 74 | Here's what happened, explained in more detail: 75 | 76 | - When we do `thingy = print('hello')`, the right side is processed 77 | first. 78 | - `print('hello')` calls the print function with the argument 79 | `'hello'`. 80 | - The function runs. It shows the word hello. 81 | - The print function **returns** None. All functions need to return 82 | something, and print returns None because there's no need to return 83 | anything else. 84 | - Now the right side has been processed. `print('hello')` returned 85 | None, so we can imagine we have None instead of `print('hello')` 86 | there, and the assignment now looks like `thingy = None`. 87 | - `thingy` is now None. 88 | 89 | Now we understand what **a return value** is. When we call the 90 | function, Python "replaces" `function(arguments)` with whatever the 91 | function returns. 92 | 93 | Calling a function without assigning the return value to anything (e.g. 94 | `print('hello')` instead of `thingy = print('hello')`) simply throws away 95 | the return value. The interactive `>>>` prompt doesn't echo the return 96 | value back because it's None. 97 | 98 | Of course, `thingy = print('hello')` is useless compared to `print('hello')` 99 | because the print function always returns None and we can do `thingy = None` 100 | without any printing. 101 | 102 | Not all functions return None. The input function can be used for 103 | getting a string from the user. 104 | 105 | ```python 106 | >>> stuff = input("Enter something:") 107 | Enter something:hello 108 | >>> stuff 109 | 'hello' 110 | >>> 111 | ``` 112 | 113 | `input("Enter something:")` showed the text `Enter something:` on the 114 | screen and waited for me to type something. I typed hello and pressed 115 | Enter. Then input returned the hello I typed as a string and it was 116 | assigned to `stuff`. 117 | 118 | Usually we want to add a space after the `:`, like this: 119 | 120 | ```python 121 | >>> stuff = input("Enter something: ") # now there's space between : and where i type 122 | Enter something: hello 123 | >>> 124 | ``` 125 | 126 | ## Handy things about print 127 | 128 | We can also print an empty line by calling print without any 129 | arguments. 130 | 131 | ```python 132 | >>> print() 133 | 134 | >>> 135 | ``` 136 | 137 | In Python, `\n` is a newline character. Printing a string that contains 138 | a newline character also prints a newline: 139 | 140 | ```python 141 | >>> print('hello\nworld') 142 | hello 143 | world 144 | >>> 145 | ``` 146 | 147 | If we want to print a real backslash, we need to **escape** it by typing 148 | two backslashes. 149 | 150 | [comment]: # (For some reason, GitHub's syntax highlighting doesn't) 151 | [comment]: # (work here.) 152 | 153 | >>> print('hello\\nworld') 154 | hello\nworld 155 | >>> 156 | 157 | We can also pass multiple arguments to the print function. We need to 158 | separate them with commas and print will add spaces between them. 159 | 160 | ```python 161 | >>> print("Hello", "World!") 162 | Hello World! 163 | >>> 164 | ``` 165 | 166 | Unlike with `+`, the arguments don't need to be strings. 167 | 168 | ```python 169 | >>> print(42, "is an integer, and the value of pi is", 3.14) 170 | 42 is an integer, and the value of pi is 3.14 171 | >>> 172 | ``` 173 | 174 | ## Variables names and built-in things 175 | 176 | In [the previous chapter](variables.md) we learned that `if` is not a 177 | valid variable name because it's a keyword. 178 | 179 | ```python 180 | >>> if = 123 181 | File "", line 1 182 | if = 123 183 | ^ 184 | SyntaxError: invalid syntax 185 | >>> 186 | ``` 187 | 188 | But `print` and `input` are not keywords, so can we use them as 189 | variable names? 190 | 191 | ```python 192 | >>> print = "hello" 193 | >>> print 194 | 'hello' 195 | >>> 196 | ``` 197 | 198 | We can, but there's a problem. Now we can't even do our hello world! 199 | 200 | ```python 201 | >>> print("Hello World!") 202 | Traceback (most recent call last): 203 | File "", line 1, in 204 | TypeError: 'str' object is not callable 205 | >>> 206 | ``` 207 | 208 | The error message complains that strings aren't callable because we just 209 | set `print` to the string `'hello'` and now we're trying to call it like 210 | a function. As you can see, **this is not a good idea** at all. Most 211 | [editors](editor-setup.md) display built-in functions with a special 212 | color, so you don't need to worry about doing this accidentally. 213 | 214 | Exit out of Python and start it again, and `print("Hello World!")` 215 | should work normally. 216 | 217 | ## Summary 218 | 219 | - `function()` calls a function without any arguments, and 220 | `function(1, 2, 3)` calls a function with 1, 2 and 3 as arguments. 221 | - When a function is called, it does something and returns something. 222 | - `function(arguments)` is "replaced" with the return value in the code 223 | that called it. For example, `stuff = function()` calls a function, 224 | and then does `stuff = the_return_value` and the return value ends 225 | up in stuff. 226 | - Python comes with `print` and `input`. They are built-in functions. 227 | - Avoid variable names that conflict with built-in functions. 228 | 229 | *** 230 | 231 | If you have trouble with this tutorial, please 232 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 233 | or [ask for help online](../getting-help.md). 234 | If you like this tutorial, please [give it a 235 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 236 | 237 | You may use this tutorial freely at your own risk. See 238 | [LICENSE](../LICENSE). 239 | 240 | [Previous](variables.md) | [Next](editor-setup.md) | 241 | [List of contents](../README.md#basics) 242 | -------------------------------------------------------------------------------- /advanced/magicmethods.md: -------------------------------------------------------------------------------- 1 | # Magic methods 2 | 3 | In [the class tutorial](../basics/classes.md) we learned to define a 4 | class like this: 5 | 6 | ```python 7 | class Website: 8 | 9 | def __init__(self, url, founding_year, free_to_use): 10 | self.url = url 11 | self.founding_year = founding_year 12 | self.free_to_use = free_to_use 13 | 14 | def info(self): 15 | print("URL:", self.url) 16 | print("Founding year:", self.founding_year) 17 | print("Free to use:", self.free_to_use) 18 | ``` 19 | 20 | After doing that we can create a new Website object like 21 | `Website('https://github.com/', 2008, True)`. Python first creates the 22 | Website object, and then calls `__init__` with the arguments we passed 23 | to Website to set it up. Methods that have a name `__like_this__` and a 24 | special meaning are called **magic methods** or **special methods**. 25 | 26 | Most magic methods define what the object has or what it can do, like 27 | "does it have a length" or "can we for loop over it". There are other 28 | magic methods that do other things also, like `__init__`. 29 | 30 | Some magic methods have a default implementation that is used if the 31 | class doesn't define anything else. For example, if we don't define an 32 | `__init__` then our class will take no arguments and it won't have any 33 | attributes by default. We'll learn more about this when we'll talk about 34 | [inheritance](classes2.md). 35 | 36 | **TODO:** write a `classes2.md`. 37 | 38 | ## Custom length 39 | 40 | Let's get started by defining an object that has a length: 41 | 42 | ```python 43 | >>> class Thing: 44 | ... def __len__(self): 45 | ... return 5 46 | ... 47 | >>> t = Thing() 48 | >>> t 49 | <__main__.Thing object at 0x7f05e4597198> 50 | >>> t.__len__() 51 | 5 52 | >>> len(t) 53 | 5 54 | >>> 55 | ``` 56 | 57 | This is what most magic methods are like. So far we have learned to use 58 | `len()` with lists, strings and other built-in types, but now we can 59 | call `len()` on our own Thing object. Many things can be fully 60 | customized with magic methods. 61 | 62 | Note that magic methods like `__len__` need to be defined in the class, 63 | just attaching an attribute called `__len__` doesn't work: 64 | 65 | ```python 66 | >>> class EmptyThing: 67 | ... pass 68 | ... 69 | >>> def length(): 70 | ... return 5 71 | ... 72 | >>> e = EmptyThing() 73 | >>> e.__len__ = length 74 | >>> e.__len__() 75 | 5 76 | >>> len(e) 77 | Traceback (most recent call last): 78 | File "", line 1, in 79 | TypeError: object of type 'EmptyThing' has no len() 80 | >>> 81 | ``` 82 | 83 | You don't really need to worry about why Python works like this, but 84 | it's explained 85 | [here](https://docs.python.org/3/reference/datamodel.html#special-method-lookup) 86 | if you want to know more about it. 87 | 88 | ## String representations 89 | 90 | You have probably noticed that typing something to the interactive `>>>` 91 | prompt is not quite the same thing as printing it. For example, 92 | strings behave like this: 93 | 94 | ```python 95 | >>> 'hello' 96 | 'hello' 97 | >>> print('hello') 98 | hello 99 | >>> 100 | ``` 101 | 102 | If you want to print something the way it's displayed on the `>>>` 103 | prompt you can use the `repr()` function. Here "repr" is short for 104 | "representation". 105 | 106 | ```python 107 | >>> message = 'hello' 108 | >>> print("the message is", repr(message)) 109 | the message is 'hello' 110 | >>> 111 | ``` 112 | 113 | Combining `repr()` with [string 114 | formatting](../basics/handy-stuff-strings.md#string-formatting) is also 115 | easy. 116 | 117 | ```python 118 | >>> print(f"the message is {repr(message)}") 119 | the message is 'hello' 120 | >>> 121 | ``` 122 | 123 | The `__repr__` magic method can be used to customize this. For example, 124 | we can do this: 125 | 126 | ```python 127 | >>> class Website: 128 | ... def __repr__(self): 129 | ... return '' 130 | ... 131 | >>> w = Website() 132 | >>> w.__repr__() 133 | '' 134 | >>> str(w) 135 | '' 136 | >>> print(w) 137 | 138 | >>> w 139 | 140 | >>> 141 | ``` 142 | 143 | The `__repr__` method can return any string, but usually you should 144 | follow one of these styles: 145 | 146 | 1. A piece of code that describes how another, similar object can be 147 | created. 148 | 149 | ```python 150 | >>> class Website: 151 | ... def __init__(self, name, founding_year): 152 | ... self.name = name 153 | ... self.founding_year = founding_year 154 | ... def __repr__(self): 155 | ... return f'Website(name={repr(self.name)}, founding_year={repr(self.founding_year)})' 156 | ... 157 | >>> github = Website('GitHub', 2008) 158 | >>> github 159 | Website(name='GitHub', founding_year=2008) 160 | >>> 161 | ``` 162 | 163 | This is useful for simple data containers like this Website class. 164 | 165 | 2. A description of the object wrapped between `<` and `>`. 166 | 167 | ```python 168 | >>> class Website: 169 | ... def __init__(self, name, founding_year): 170 | ... self.name = name 171 | ... self.founding_year = founding_year 172 | ... def __repr__(self): 173 | ... return f'' 174 | ... 175 | >>> github = Website('GitHub', 2008) 176 | >>> github 177 | 178 | >>> 179 | ``` 180 | 181 | This style is good when you want to tell more about the object than 182 | you can by showing the `__init__` arguments. Python's built-in 183 | things also use this style more: 184 | 185 | ```python 186 | >>> import random 187 | >>> random 188 | 189 | >>> 190 | ``` 191 | 192 | ## Other magic methods 193 | 194 | There are many more magic methods, and I don't see any reason to list 195 | them all here. [The official 196 | documentation](https://docs.python.org/3/reference/datamodel.html) has 197 | more information about magic methods if you need it. We'll go through 198 | using the most important magic methods in the rest of this tutorial, so 199 | if you just keep reading you'll learn more about them. 200 | 201 | ## When should we use magic methods? 202 | 203 | There's nothing wrong with using `__init__` everywhere, but other than 204 | that, magic methods are usually not needed. `website.has_user(user)` and 205 | `user in website.userlist` are way better than something weird that we 206 | could do with magic methods like `user @ website`. People expect 207 | `website.has_user(user)` check if a user has registered on the website, 208 | but nobody can guess what `user @ website` does. Explicit is better than 209 | implicit, and simple is better than complex. 210 | 211 | On the other hand, using magic methods when needed can turn something 212 | good into something great. Especially the `__repr__` method is useful 213 | because people can get a good idea of what an object is by just looking 214 | at it on the `>>>` prompt or printing it. I recommend using `__repr__` 215 | methods in things that other people will import and use in their 216 | projects, but `__repr__` methods aren't worth it for simple scripts that 217 | are not meant to be imported. 218 | 219 | ## Summary 220 | 221 | - Magic methods define what instances of a class can do and how, like 222 | "does it have a length" or "what does it look like when I print it". 223 | - Python uses magic methods to implement many things internally, and we 224 | can customize everything by implementing the magic methods 225 | ourselves. 226 | - Defining custom `__repr__` methods is often a good idea when making 227 | things that other people will import and use in their own projects, 228 | and the `__init__` method is very useful for many things. 229 | Other than that, magic methods are usually not worth it. 230 | 231 | *** 232 | 233 | If you have trouble with this tutorial, please 234 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 235 | or [ask for help online](../getting-help.md). 236 | If you like this tutorial, please [give it a 237 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 238 | 239 | You may use this tutorial freely at your own risk. See 240 | [LICENSE](../LICENSE). 241 | 242 | [Previous](functions.md) | [Next](iters.md) | 243 | [List of contents](../README.md#advanced) 244 | -------------------------------------------------------------------------------- /basics/larger-program.md: -------------------------------------------------------------------------------- 1 | # Writing a larger program 2 | 3 | Now we know enough about Python for creating a program that is actually 4 | useful. Awesome! 5 | 6 | In this tutorial we'll write a program that reads questions and answers 7 | in a text file and asks them. For example, this file would make the 8 | program ask what "text displaying function" and "text asking function" 9 | are: 10 | 11 | ``` 12 | text displaying function = print 13 | text asking function = input 14 | ``` 15 | 16 | **Save this example file to questions.txt**, we'll need it later. 17 | 18 | This might seem useless to you right now, but a program like this can 19 | actually be really useful for learning different kinds of things. I 20 | originally wrote a program like this to study words of a foreign 21 | language, but then I realized that I could study pretty much anything 22 | with it. 23 | 24 | But there are many things the program needs to do and writing it seems 25 | really difficult and complicated! How the heck can we do this? 26 | 27 | ## Write functions 28 | 29 | Our program will need to do several different things: 30 | 31 | 1. Read the questions from a file. 32 | 2. Ask the questions. 33 | 3. Print statistics about how many questions were answered correctly 34 | and how many wrong. 35 | 36 | Now everything seems much easier. We know how to do each of these steps 37 | one by one, but doing it all at once would be difficult. In situations 38 | like this it's important to [define functions](defining-functions.md). 39 | We are going to write a `read_questions` function, an `ask_questions` 40 | function and a `stats` function. 41 | 42 | Let's start with the function that reads the question file: 43 | 44 | ```python 45 | def read_questions(filename): 46 | answers = {} 47 | with open(filename, 'r') as f: 48 | for line in f: 49 | line = line.strip() 50 | if line != '': 51 | question, answer = line.split('=') 52 | answers[question.strip()] = answer.strip() 53 | return answers 54 | ``` 55 | 56 | At this point it's best to try out the function to see how it works. You 57 | need to create a `questions.txt` file like the one in the beginning of 58 | this tutorial if you didn't create it already. 59 | 60 | **TODO:** Instructions for using the -i switch. 61 | 62 | ```python 63 | >>> read_questions('questions.txt') 64 | {'text displaying function': 'print', 'text asking function': 'input'} 65 | >>> 66 | ``` 67 | 68 | If your function doesn't work correctly it doesn't matter, and fixing 69 | the problem is easy because the function is so short. This is one of the 70 | reasons why we write functions. 71 | 72 | Next we'll write the rest of the functions the same way, first writing 73 | and then testing and fixing. Here are my versions of them: 74 | 75 | ```python 76 | def ask_questions(answers): 77 | correct = [] 78 | wrong = [] 79 | 80 | for question, answer in answers.items(): 81 | if input(question + ' = ').strip() == answer: 82 | print("Correct!") 83 | correct.append(question) 84 | else: 85 | print(f"Wrong! The correct answer is {answer}.") 86 | wrong.append(question) 87 | 88 | return (correct, wrong) 89 | 90 | 91 | def stats(correct, wrong, answers): 92 | print("\n**** STATS ****\n") 93 | print("You answered", len(correct), "questions correctly and", 94 | len(wrong), "questions wrong.") 95 | 96 | if wrong: 97 | print("These would have been the correct answers:") 98 | for question in wrong: 99 | print(' ', question, '=', answers[question]) 100 | ``` 101 | 102 | Note that these functions have some empty lines in them and there are 103 | two empty lines between the functions. This makes the code a bit longer, 104 | but it's a lot easier to read this way. 105 | 106 | Let's try out the functions. 107 | 108 | ```python 109 | >>> answers = read_questions('questions.txt') 110 | >>> correct, wrong = ask_questions(answers) 111 | text displaying function = print 112 | Correct! 113 | text asking function = elif 114 | Wrong! The correct answer is input. 115 | >>> correct 116 | ['text displaying function'] 117 | >>> wrong 118 | ['text asking function'] 119 | >>> stats(correct, wrong, answers) 120 | 121 | **** STATS **** 122 | 123 | You answered 1 questions right and 1 questions wrong. 124 | These would have been the correct answers: 125 | text asking function = input 126 | >>> 127 | ``` 128 | 129 | Everything is working! Now we just need something that runs everything 130 | because we don't want to type this out on the `>>>` prompt every time. 131 | 132 | You might have noticed that the stats function printed `1 questions` 133 | instead of `1 question`, and it looks a bit weird. You can modify the 134 | `print_stats` function to fix this if you want to. 135 | 136 | ## The main function 137 | 138 | The last function in a program like this is usually called `main` and it 139 | runs the program using other functions. Our main function consists of 140 | mostly the same pieces of code that we just tried out on the `>>>` 141 | prompt. 142 | 143 | ```python 144 | def main(): 145 | filename = input("Name of the question file: ") 146 | answers = read_questions(filename) 147 | correct, wrong = ask_questions(answers) 148 | stats(correct, wrong, answers) 149 | ``` 150 | 151 | The last thing we need to add is these two lines: 152 | 153 | ```python 154 | if __name__ == '__main__': 155 | main() 156 | ``` 157 | 158 | The `__name__` variable is set differently depending on how we run the 159 | file, and it's `'__main__'` when we run the file directly instead of 160 | importing. So if we run the file normally it asks us the words, and if 161 | we import it instead we can still run the functions one by one. If you 162 | want to know more about `__name__` just make a file that prints it and 163 | run it in different ways. 164 | 165 | Now the whole program looks like this: 166 | 167 | ```python 168 | def read_questions(filename): 169 | answers = {} 170 | with open(filename, 'r') as f: 171 | for line in f: 172 | line = line.strip() 173 | if line != '': 174 | question, answer = line.split('=') 175 | answers[question.strip()] = answer.strip() 176 | return answers 177 | 178 | 179 | def ask_questions(answers): 180 | correct = [] 181 | wrong = [] 182 | 183 | for question, answer in answers.items(): 184 | if input(f'{question} = ').strip() == answer: 185 | print("Correct!") 186 | correct.append(question) 187 | else: 188 | print(f"Wrong! The correct answer is {answer}.") 189 | wrong.append(question) 190 | 191 | return (correct, wrong) 192 | 193 | 194 | def stats(correct, wrong, answers): 195 | print("\n**** STATS ****\n") 196 | print("You answered", len(correct), "questions correctly and", 197 | len(wrong), "questions wrong.") 198 | 199 | if wrong: 200 | print("These would have been the correct answers:") 201 | for question in wrong: 202 | print(' ', question, '=', answers[question]) 203 | 204 | 205 | def main(): 206 | filename = input("Name of the question file: ") 207 | answers = read_questions(filename) 208 | correct, wrong = ask_questions(answers) 209 | stats(correct, wrong, answers) 210 | 211 | if __name__ == '__main__': 212 | main() 213 | ``` 214 | 215 | This is just the beginning. Now [you can](../LICENSE) take your word 216 | asking program and make your own version of it that suits **your** 217 | needs. Then you can share it with your friends so they will find it 218 | useful as well. 219 | 220 | ## Summary 221 | 222 | - Make multiple functions when your program needs to do multiple things. 223 | Each function should do one thing. 224 | - Try out the functions on the `>>>` prompt when you want to check if 225 | they work correctly. 226 | - `__name__` is `'__main__'` when the program is supposed to run, and 227 | something else when it's imported. 228 | 229 | *** 230 | 231 | If you have trouble with this tutorial, please 232 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 233 | or [ask for help online](../getting-help.md). 234 | If you like this tutorial, please [give it a 235 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 236 | 237 | You may use this tutorial freely at your own risk. See 238 | [LICENSE](../LICENSE). 239 | 240 | [Previous](defining-functions.md) | [Next](what-is-true.md) | 241 | [List of contents](../README.md#basics) 242 | -------------------------------------------------------------------------------- /basics/what-is-programming.md: -------------------------------------------------------------------------------- 1 | # What is programming? 2 | 3 | **Feel free to [skip this part](#how-to-read-this-tutorial) if you 4 | already know everything it's talking about.** 5 | 6 | As a computer user you know that computers don't have feelings. They 7 | don't work any faster or slower depending on if we're angry at them or 8 | if we're happy. Computers can perform millions of calculations per 9 | second, but they require us to tell them exactly what to do. If they do 10 | something else than we want them to do the problem is usually that they 11 | don't understand our instructions the way we understand them. 12 | 13 | The only big difference between programming and what you're familiar 14 | with already is that instead of clicking buttons to do things we write 15 | the instructions using a **programming language**. Most programming 16 | languages consist of English words, digits and some characters that have 17 | special meanings. 18 | 19 | Unlike people often think, programming is usually not complicated. Large 20 | programs are always made of **small, simple pieces**, and those pieces 21 | are written one by one. Programming languages are made to be used by 22 | humans, so if there's an easy way to do something and a difficult way to 23 | do something, you should use the easier way. 24 | 25 | ## What do I need? 26 | 27 | First of all, **you don't need to be good at math**. Some programmers 28 | are good at math, some are not. Programming and math are two separate 29 | things and being good or bad at one doesn't mean you are automatically 30 | good or bad at the other. 31 | 32 | You also don't need a powerful computer. I could do almost all of my 33 | programming on a 12-year-old computer if I needed to. Fast computers are 34 | nice to work with, but you don't need them. 35 | 36 | Programming takes time like all hobbies do. Some people learn it 37 | quickly, and some people don't. I don't expect you to read this tutorial 38 | in a couple hours and then master everything it's talking about. Take 39 | your time with things, and remember that I learned to program slowly. 40 | 41 | ## Getting started 42 | 43 | This tutorial uses a programming language called Python because it's 44 | easy to learn and we can do many different things with it. For example, 45 | we can create our own applications that have buttons that people can 46 | click instead of just using applications written by others. 47 | 48 | Before we can get started with Python we need to know how to write some of 49 | Python's special characters with our keyboards. Unfortunately I don't know 50 | which keys you need to press to produce these characters because your keyboard 51 | is probably different than mine. But the keyboard can tell what you 52 | need to press. For example, my Finnish keyboard has a key like this: 53 | 54 | ![A key on my keyboard.](../images/key.png) 55 | 56 | Here's what the characters on this key mean: 57 | 58 | - I can type a number 7 by pressing this key without holding down other keys 59 | at the same time. 60 | - I can type a `/` character by holding down the shift key (on the left edge 61 | of the keyboard, between Ctrl and CapsLock) and pressing this key. 62 | - I can type a `{` character by holding down AltGr (on the bottom of the 63 | keyboard, on the right side of the spacebar) and pressing this key. 64 | Holding down Ctrl and Alt instead of AltGr may also work. 65 | 66 | The only key that doesn't have anything written on it is spacebar. It's the 67 | big, wide key that's closest to you. Another key that's used for producing 68 | whitespace is tab, the key above CapsLock. 69 | 70 | In this tutorial we need to know how to type these characters. We'll learn 71 | their meanings later. 72 | 73 | | Character | Names | 74 | |-----------|---------------------------------------| 75 | | `+` | plus | 76 | | `-` | minus, dash | 77 | | `_` | underscore | 78 | | `*` | star, asterisk | 79 | | `/` | forwardslash (it's leaning forward) | 80 | | `\` | backslash (it's leaning back) | 81 | | `=` | equals sign | 82 | | `%` | percent sign | 83 | | `.` | dot | 84 | | `,` | comma | 85 | | `:` | colon | 86 | | `?` | question mark | 87 | | `!` | exclamation mark | 88 | | `<` `>` | less-than and greater-than signs | 89 | | `'` `"` | single quote and double quote | 90 | | `#` | hashtag | 91 | | `()` | parentheses | 92 | | `[]` | square brackets, brackets | 93 | | `{}` | curly braces, braces, curly brackets | 94 | 95 | That may seem like many characters, but you probably know many of them already 96 | so it shouldn't be a problem. 97 | 98 | ## How to read this tutorial 99 | 100 | I've done my best to make this tutorial as easy to follow as possible. Other 101 | people have commented on this and helped me improve this a lot also. But what 102 | should you do if you have a problem with the tutorial? 103 | 104 | 1. Try the example code yourself. 105 | 2. Read the code and the explanation for it again. 106 | 3. If there's something you haven't seen before in the tutorial and it's 107 | not explained, try to find it in the previous chapters. 108 | 4. If you can't find what you're looking for or you still have trouble 109 | understanding the tutorial or any other problems with the tutorial, 110 | please [tell me about it](../contact-me.md). I want to improve this 111 | tutorial so other readers won't have the same problem as you have. 112 | 5. See [Getting help](../getting-help.md) if you can't contact me for some 113 | reason. 114 | 115 | You are free to combine this tutorial with other learning resources. If this 116 | tutorial isn't exactly what you're looking for you don't need to stick with 117 | nothing but this. You can find another tutorial and mix the tutorials however 118 | you want as long as you **make sure that you understand everything you read**. 119 | 120 | One of the most important things with learning to program is to **not 121 | fear mistakes**. If you make a mistake, your computer will not break in 122 | any way. You'll get an error message that tells you what's wrong and 123 | where. Even professional programmers do mistakes and get error messages 124 | all the time, and there's nothing wrong with it. 125 | 126 | If you want to know what some piece of code in this tutorial does just 127 | **try it and see**. It's practically impossible to break anything 128 | accidentally with the things you will learn by reading this tutorial, 129 | so you are free to try out all the examples however you want and change 130 | them to do whatever you want. 131 | 132 | Even though a good tutorial is an important part about learning to 133 | program, you also need to learn to make your own things. Use what you 134 | have learned, and create something with it. 135 | 136 | ## But reading is boring! 137 | 138 | This chapter is probably the most boring chapter in the whole tutorial. 139 | Other chapters contain much less text and much more code. You can also 140 | get pretty far by just reading the code, and then reading the text only 141 | if you don't understand the code. 142 | 143 | ## Summary 144 | 145 | - Now you should know what programming and programming languages are. 146 | - You don't need to be good at math and you don't need a new computer. 147 | - Complicated programs consist of simple pieces. 148 | - You don't need to remember how to type different characters. Just find the 149 | character on your keyboard and press the key, holding down shift or AltGr 150 | as needed. 151 | - Make sure you understand everything you read. 152 | - Experiment with things freely and don't fear mistakes. 153 | - Error messages are our friends. 154 | - Let me know if you have trouble with this tutorial. 155 | - Now we're ready to [install Python](installing-python.md) and 156 | [get started](getting-started.md)! 157 | 158 | *** 159 | 160 | If you have trouble with this tutorial, please 161 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 162 | or [ask for help online](../getting-help.md). 163 | If you like this tutorial, please [give it a 164 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 165 | 166 | You may use this tutorial freely at your own risk. See 167 | [LICENSE](../LICENSE). 168 | 169 | [Previous](../README.md) | [Next](installing-python.md) | 170 | [List of contents](../README.md#basics) 171 | -------------------------------------------------------------------------------- /basics/if.md: -------------------------------------------------------------------------------- 1 | # If, else and elif 2 | 3 | ## Using if statements 4 | 5 | Now we know what True and False are. 6 | 7 | ```python 8 | >>> 1 == 1 9 | True 10 | >>> 1 == 2 11 | False 12 | >>> 13 | >>> its_raining = True 14 | >>> its_raining 15 | True 16 | >>> 17 | ``` 18 | 19 | But what if we want to execute different code depending on something? 20 | That's when `if` comes in. 21 | 22 | ```python 23 | >>> its_raining = True 24 | >>> if its_raining: 25 | ... print("It's raining!") 26 | ... 27 | It's raining! 28 | >>> its_raining = False 29 | >>> if its_raining: 30 | ... print("It's raining!") # nothing happens 31 | ... 32 | >>> 33 | ``` 34 | 35 | The prompt changed from `>>>` to `...`. It meant that Python was 36 | expecting me to keep typing. When I was done, I just pressed Enter 37 | twice. My code was executed and the prompt went back to `>>>`. 38 | 39 | An important thing to notice is that the line with a print is 40 | **indented**. You can press the tab key, or if it doesn't work 41 | just press space a few times. 42 | 43 | But why is that `if its_raining` instead of `if(its_raining)`? 44 | 45 | Earlier we learned that `if` is a **keyword**. 46 | 47 | ```python 48 | >>> if = 123 49 | File "", line 1 50 | if = 123 51 | ^ 52 | SyntaxError: invalid syntax 53 | >>> 54 | ``` 55 | 56 | **Functions** like `print` need `()` after their name to work. But `if` 57 | is **a keyword**, not a function, so it doesn't need `()`. Python has 58 | separate functions and keywords because it's possible to create custom 59 | functions, but it's not possible to create custom keywords. That's why 60 | keywords are usually used for "magic" things that would be difficult to 61 | do with just functions. 62 | 63 | Also note that if statements check the condition once only, so if we 64 | set it to false later the if statement won't notice it. 65 | 66 | ```python 67 | >>> its_raining = True 68 | >>> if its_raining: 69 | ... its_raining = False 70 | ... print("It's not raining, but this runs anyway.") 71 | ... 72 | It's not raining, but this runs anyway. 73 | >>> 74 | ``` 75 | 76 | ## Using else 77 | 78 | What if we want to print a different message if it's not raining? We 79 | could do something like this: 80 | 81 | ```python 82 | its_raining = True # you can change this to False 83 | its_not_raining = not its_raining # False if its_raining, True otherwise 84 | 85 | if its_raining: 86 | print("It's raining!") 87 | if its_not_raining: 88 | print("It's not raining.") 89 | ``` 90 | 91 | Note that this code example doesn't start with `>>>`, so you should 92 | [save it to a file and run the file](editor-setup.md). 93 | 94 | Now our program will print a different value depending on what the 95 | value of `its_raining` is. 96 | 97 | We can also add `not its_raining` directly to the second if statement: 98 | 99 | ```python 100 | its_raining = True 101 | 102 | if its_raining: 103 | print("It's raining!") 104 | if not its_raining: 105 | print("It's not raining.") 106 | ``` 107 | 108 | But we can make it even better by using `else`. 109 | 110 | ```python 111 | its_raining = True 112 | 113 | if its_raining: 114 | print("It's raining!") 115 | else: 116 | print("It's not raining.") 117 | ``` 118 | 119 | The else part simply runs when the if statement doesn't run. It doesn't 120 | check the condition again. 121 | 122 | ```python 123 | >>> its_raining = True 124 | >>> if its_raining: 125 | ... its_raining = False 126 | ... else: 127 | ... print("It's not raining, but this still doesn't run.") 128 | ... 129 | >>> 130 | ``` 131 | 132 | By combining `else` with the input function we can make a program that 133 | asks for a password and checks if it's correct. 134 | 135 | ```python 136 | print("Hello!") 137 | password = input("Enter your password: ") 138 | 139 | if password == "secret": 140 | print("That's correct, welcome!") 141 | else: 142 | print("Access denied.") 143 | ``` 144 | 145 | The program prints different things depending on what we enter: 146 | 147 | ``` 148 | Hello! 149 | Enter your password: secret 150 | Welcome! 151 | ``` 152 | 153 | ``` 154 | Hello! 155 | Enter your password: lol 156 | Access denied. 157 | ``` 158 | 159 | Using the input function for passwords doesn't work very well because 160 | we can't hide the password with asterisks. There are better ways to get 161 | a password from the user, but you shouldn't worry about that just yet. 162 | 163 | ## Avoiding many levels of indentation with elif 164 | 165 | If we have more than one condition to check, we could do this: 166 | 167 | ```python 168 | print("Hello!") 169 | word = input("Enter something: ") 170 | 171 | if word == "hi": 172 | print("Hi to you too!") 173 | else: 174 | if word == "hello": 175 | print("Hello hello!") 176 | else: 177 | if word == "howdy": 178 | print("Howdyyyy!") 179 | else: 180 | if word == "hey": 181 | print("Hey hey hey!") 182 | else: 183 | if word == "gday m8": 184 | print("Gday 4 u 2!") 185 | else: 186 | print("I don't know what", word, "means.") 187 | ``` 188 | 189 | This code is a mess. We need to indent more every time we want to check 190 | for more words. Here we check for 5 different words, so we have 5 levels 191 | of indentation. If we would need to check 30 words, the code would 192 | become really wide and it would be hard to work with. 193 | 194 | Instead of typing `else`, indenting more and typing an `if` we can 195 | simply type `elif`, which is short for `else if`. Like this: 196 | 197 | ```python 198 | print("Hello!") 199 | word = input("Enter something: ") 200 | 201 | if word == "hi": 202 | print("Hi to you too!") 203 | elif word == "hello": 204 | print("Hello hello!") 205 | elif word == "howdy": 206 | print("Howdyyyy!") 207 | elif word == "hey": 208 | print("Hey hey hey!") 209 | elif word == "gday m8": 210 | print("Gday 4 u 2!") 211 | else: 212 | print("I don't know what", word, "means.") 213 | ``` 214 | 215 | Now the program is shorter and much easier to read. 216 | 217 | Note that the `elif` parts only run if nothing before them matches, and 218 | the `else` runs only when none of the `elifs` match. If we would have 219 | used `if` instead, all possible values would be always checked and the 220 | `else` part would run always except when word is `"gday m8"`. This is 221 | why we use `elif` instead of `if`. 222 | 223 | For example, this program prints only `hello`... 224 | 225 | ```python 226 | if 1 == 1: 227 | print("hello") 228 | elif 1 == 2: 229 | print("this is weird") 230 | else: 231 | print("world") 232 | ``` 233 | 234 | ...but this prints `hello` *and* `world`: 235 | 236 | ```python 237 | if 1 == 1: 238 | print("hello") 239 | if 1 == 2: 240 | print("this is weird") 241 | else: 242 | print("world") 243 | ``` 244 | 245 | Now the `else` belongs to the `if 1 == 2` part and **it has nothing to 246 | do with the `if 1 == 1` part**. On the other hand, the elif version 247 | **grouped the multiple ifs together** and the `else` belonged to all of 248 | them. Adding a blank line makes this obvious: 249 | 250 | ```python 251 | if 1 == 1: 252 | print("hello") 253 | 254 | if 1 == 2: 255 | print("this is weird") 256 | else: 257 | print("world") 258 | ``` 259 | 260 | In general, adding blank lines to appropriate places is a good idea. If 261 | you are asked to "fix code", feel free to add missing blank lines. 262 | 263 | ## Summary 264 | 265 | - If a code example starts with `>>>` run it on the interactive prompt. 266 | If it doesn't, write it to a file and run that file. 267 | - Indentation is important in Python. 268 | - Indented code under an if statement runs if the condition is true. 269 | - We can also add an else statement. Indented code under it will run 270 | if the code under the if statement does not run. 271 | - elif is short for else if. 272 | 273 | ## Exercises 274 | 275 | 1. This program contains several problems. Copy-paste it to a file, 276 | then try to run it, fix the errors you got, try to run it again and 277 | keep going until it works. 278 | 279 | ```python 280 | print(Hello!) 281 | something == input('Enter something: ) 282 | print('You entered:' something) 283 | ``` 284 | 285 | 2. Fix this program the same way: 286 | 287 | ```python 288 | print('Hello!') 289 | something = input("Enter something: ") 290 | if something = 'hello': 291 | print("Hello for you too!") 292 | 293 | elif something = 'hi' 294 | print('Hi there!') 295 | else: 296 | print("I don't know what," something, "means.") 297 | ``` 298 | 299 | 3. Write a program into a file that asks the user to write a word and 300 | then prints that word 1000 times. For example, if the user enters 301 | `hi` the program would reply `hihihihihihihihi` ... 302 | 303 | 4. Add spaces between the words, so the output is like `hi hi hi hi` ... 304 | 305 | 5. Make something that asks the user to enter two words, and prints 306 | 1000 of each with spaces in between. For example, if the user 307 | enters `hello` and `hi` the program would print 308 | `hello hi hello hi hello hi hello hi hello hi` ... 309 | 310 | 6. Make a program that asks for a password and prints `Welcome!`, 311 | `Access denied` or `You didn't enter anything` depending on whether 312 | the user entered the correct password, a wrong password, or nothing 313 | at all by pressing Enter without typing anything. 314 | 315 | 316 | The answers are [here](answers.md#if-else-and-elif). 317 | 318 | *** 319 | 320 | If you have trouble with this tutorial, please 321 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 322 | or [ask for help online](../getting-help.md). 323 | If you like this tutorial, please [give it a 324 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 325 | 326 | You may use this tutorial freely at your own risk. See 327 | [LICENSE](../LICENSE). 328 | 329 | [Previous](editor-setup.md) | [Next](handy-stuff-strings.md) | 330 | [List of contents](../README.md#basics) 331 | -------------------------------------------------------------------------------- /basics/variables.md: -------------------------------------------------------------------------------- 1 | # Variables, Booleans and None 2 | 3 | ## Variables 4 | 5 | Variables are easy to understand. They simply **point to values**. 6 | 7 | ```python 8 | >>> a = 1 # create a variable called a that points to 1 9 | >>> b = 2 # create another variable 10 | >>> a # get the value that the variable points to 11 | 1 12 | >>> b 13 | 2 14 | >>> 15 | ``` 16 | 17 | Let's draw a diagram of these variables. 18 | 19 | ![Variable diagram](../images/variables1.png) 20 | 21 | We can also change the value of a variable after setting it. 22 | 23 | ```python 24 | >>> a = 2 # make a point to 2 instead of 1 25 | >>> a 26 | 2 27 | >>> 28 | ``` 29 | 30 | So now our diagram looks like this: 31 | 32 | ![Variable diagram](../images/variables2.png) 33 | 34 | Setting a variable to another variable gets the value of the other 35 | variable and sets the first variable to point to that value. 36 | 37 | ```python 38 | >>> a = 1 39 | >>> b = a # this makes b point to 1, not a 40 | >>> a = 5 41 | >>> b # b didn't change when a changed 42 | 1 43 | >>> 44 | ``` 45 | 46 | Trying to access a variable that is not defined creates an error 47 | message. 48 | 49 | ```python 50 | >>> thingy 51 | Traceback (most recent call last): 52 | File "", line 1, in 53 | NameError: name 'thingy' is not defined 54 | >>> 55 | ``` 56 | 57 | Variables are simple to understand, but there are a few details that we 58 | need to keep in mind: 59 | 60 | - Variables always point to a value, **they never point to other 61 | variables**. That's why the arrows in our diagrams always go left 62 | to right. 63 | - Multiple variables can point to the same value, but one variable 64 | cannot point to multiple values. 65 | - The values that variables point to can point to other values also. 66 | We'll learn more about that when we'll talk about 67 | [lists](lists-and-tuples.md). 68 | 69 | Variables are an important part of most programming languages, and they 70 | allow programmers to write much larger programs than they could write 71 | without variables. 72 | 73 | Variable names are case-sensitive, like many other things in Python. 74 | 75 | ```python 76 | >>> thing = 1 77 | >>> THING = 2 78 | >>> thIng = 3 79 | >>> thing 80 | 1 81 | >>> THING 82 | 2 83 | >>> thIng 84 | 3 85 | >>> 86 | ``` 87 | 88 | There are also words that cannot be used as variable names 89 | because they are reserved by Python itself and have a special meaning. 90 | They are called **keywords**, and we can run `help('keywords')` 91 | to see the full list if we want to. 92 | We'll learn to use most of them later in this tutorial. Trying to use a 93 | keyword as a variable name causes a syntax error. 94 | 95 | ```python 96 | >>> if = 123 97 | File "", line 1 98 | if = 123 99 | ^ 100 | SyntaxError: invalid syntax 101 | >>> 102 | ``` 103 | 104 | When assigning something to a variable using a `=`, the right side of 105 | the `=` is always executed before the left side. This means that we can 106 | do something with a variable on the right side, then assign the result 107 | back to the same variable on the left side. 108 | 109 | ```python 110 | >>> a = 1 111 | >>> a = a + 1 112 | >>> a 113 | 2 114 | >>> 115 | ``` 116 | 117 | To do something to a variable (for example, to add something to it) we 118 | can also use `+=`, `-=`, `*=` and `/=` instead of `+`, `-`, `*` and 119 | `/`. The "advanced" `%=`, `//=` and `**=` also work. 120 | 121 | ```python 122 | >>> a += 2 # a = a + 2 123 | >>> a -= 2 # a = a - 2 124 | >>> a *= 2 # a = a * 2 125 | >>> a /= 2 # a = a / 2 126 | >>> 127 | ``` 128 | 129 | This is not limited to integers. 130 | 131 | ```python 132 | >>> a = 'hello' 133 | >>> a *= 3 134 | >>> a += 'world' 135 | >>> a 136 | 'hellohellohelloworld' 137 | >>> 138 | ``` 139 | 140 | Now we also understand why typing hello to the prompt didn't work in 141 | the beginning of this tutorial. But we can assign something to a 142 | variable called hello and then type hello: 143 | 144 | ```python 145 | >>> hello = 'hello there' 146 | >>> hello 147 | 'hello there' 148 | >>> 149 | ``` 150 | 151 | ## Good and bad variable names 152 | 153 | Variable names can be multiple characters long. They can contain 154 | uppercase characters, numbers and some other characters, but most of the 155 | time we should use simple, lowercase variable names. We can also use 156 | underscores. For example, these variable names are good: 157 | 158 | ```python 159 | >>> magic_number = 123 160 | >>> greeting = "Hello World!" 161 | >>> 162 | ``` 163 | 164 | Don't use variable names like this, **these variables are _bad_**: 165 | 166 | ```python 167 | >>> magicNumber = 3.14 # looks weird 168 | >>> Greeting = "Hello there!" # also looks weird 169 | >>> x = "Hello again!" # what the heck is x? 170 | >>> 171 | ``` 172 | 173 | All of these variables work just fine, but other Python programmers 174 | don't want you to use them. Most Python code doesn't use variable names 175 | that contain UpperCase letters like `magicNumber` and `Greeting`, so 176 | other people reading your code will think it looks weird if you use 177 | them. The problem with `x` is that it's too short, and people have no 178 | idea what it is. Remember that mathematicians like figuring out what x 179 | is, but programmers hate that. 180 | 181 | ## Booleans 182 | 183 | There are two Boolean values, True and False. In Python, and in many 184 | other programming languages, `=` is assigning and `==` is comparing. 185 | `a = 1` sets a to 1, and `a == 1` checks if a equals 1. 186 | 187 | ```python 188 | >>> a = 1 189 | >>> a == 1 190 | True 191 | >>> a = 2 192 | >>> a == 1 193 | False 194 | >>> 195 | ``` 196 | 197 | `a == 1` is the same as `(a == 1) == True`, but `a == 1` is more 198 | readable, so most of the time we shouldn't write `== True` anywhere. 199 | 200 | ```python 201 | >>> a = 1 202 | >>> a == 1 203 | True 204 | >>> (a == 1) == True 205 | True 206 | >>> a = 2 207 | >>> a == 1 208 | False 209 | >>> (a == 1) == True 210 | False 211 | >>> 212 | ``` 213 | 214 | ## None 215 | 216 | None is Python's "nothing" value. It behaves just like any other value, 217 | and it's often used as a default value for different kinds of things. 218 | Right now it might seem useless but we'll find a bunch of ways to use 219 | None later. 220 | 221 | None's behavior on the interactive prompt might be a bit confusing at 222 | first: 223 | 224 | ```python 225 | >>> thingy = None 226 | >>> thingy 227 | >>> 228 | ``` 229 | 230 | That was weird! We set thingy to None, but typing `thingy` didn't echo 231 | back None. 232 | 233 | This is because the prompt never echoes back None. That is handy, 234 | because many things result in None, and it would be annoying to see 235 | None coming up all the time. 236 | 237 | If we want to see a None on the interactive prompt, we can use print. 238 | 239 | ```python 240 | >>> print(thingy) 241 | None 242 | >>> 243 | ``` 244 | 245 | Another confusing thing is that if we do something weird to None we get 246 | error messages that talk about NoneType object. The NoneType object they 247 | are talking about is always None. We'll learn more about what attributes 248 | and calling are later. 249 | 250 | ```python 251 | >>> None.hello # None has no attribute 'hello' 252 | Traceback (most recent call last): 253 | File "", line 1, in 254 | AttributeError: 'NoneType' object has no attribute 'hello' 255 | >>> None() # None is not callable 256 | Traceback (most recent call last): 257 | File "", line 1, in 258 | TypeError: 'NoneType' object is not callable 259 | >>> 260 | ``` 261 | 262 | ## Other comparing operators 263 | 264 | So far we've used `==`, but there are other operators also. This list 265 | probably looks awfully long, but it's actually quite easy to learn. 266 | 267 | | Usage | Description | True examples | 268 | |-----------|-----------------------------------|-----------------------| 269 | | `a == b` | a is equal to b | `1 == 1` | 270 | | `a != b` | a is not equal to b | `1 != 2` | 271 | | `a > b` | a is greater than b | `2 > 1` | 272 | | `a >= b` | a is greater than or equal to b | `2 >= 1`, `1 >= 1` | 273 | | `a < b` | a is less than b | `1 < 2` | 274 | | `a <= b` | a is less than or equal to b | `1 <= 2`, `1 <= 1` | 275 | 276 | We can also combine multiple comparisons. This table assumes that a and 277 | b are Booleans. 278 | 279 | | Usage | Description | True example | 280 | |-----------|-------------------------------------------|-----------------------------------| 281 | | `a and b` | a is True and b is True | `1 == 1 and 2 == 2` | 282 | | `a or b` | a is True, b is True or they're both True | `False or 1 == 1`, `True or True` | 283 | 284 | `not` can be used for negations. If `value` is True, `not value` is 285 | False, and if `value` is False, `not value` is True. 286 | 287 | There's also `is`, but don't use it instead of `==` unless you know 288 | what you are doing. We'll learn more about it later. 289 | 290 | ## Summary 291 | 292 | - Variables have a name and a value. We can create or change variables 293 | with `name = value`. 294 | - `thing += stuff` does the same thing as `thing = thing + stuff`. 295 | - Use lowercase variable names and remember that programmers hate 296 | figuring out what x is. 297 | - `=` means assigning and `==` means comparing. 298 | - True and False are Booleans. Comparing values results in a Boolean. 299 | - None is a value that we'll find useful later. When error messages say 300 | `NoneType object` they mean None. 301 | 302 | *** 303 | 304 | If you have trouble with this tutorial, please 305 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 306 | or [ask for help online](../getting-help.md). 307 | If you like this tutorial, please [give it a 308 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 309 | 310 | You may use this tutorial freely at your own risk. See 311 | [LICENSE](../LICENSE). 312 | 313 | [Previous](the-way-of-the-program.md) | [Next](using-functions.md) | 314 | [List of contents](../README.md#basics) 315 | -------------------------------------------------------------------------------- /advanced/functions.md: -------------------------------------------------------------------------------- 1 | # Advanced things with functions 2 | 3 | Now we know [how to define functions](../basics/defining-functions.md). 4 | Functions can take arguments, and they will end up with local variables 5 | that have the same name. Like this: 6 | 7 | ```python 8 | def print_box(message, border='*'): 9 | print(border * (len(message) + 4)) 10 | print(border, message, border) 11 | print(border * (len(message) + 4)) 12 | 13 | print_box("hello") 14 | ``` 15 | 16 | In this chapter we'll learn more things we can do with defining 17 | functions and how they are useful. 18 | 19 | ## Multiple return values 20 | 21 | Function can take multiple arguments, but they can only return one 22 | value. But sometimes it makes sense to return multiple values as well: 23 | 24 | ```python 25 | def login(): 26 | username = input("Username: ") 27 | password = input("Password: ") 28 | # how the heck are we going to return these? 29 | ``` 30 | 31 | The best solution is to return a tuple of values, and just unpack that 32 | wherever the function is called: 33 | 34 | ```python 35 | def login(): 36 | ... 37 | return (username, password) 38 | 39 | 40 | username, password = login() 41 | ... 42 | ``` 43 | 44 | That gets kind of messy if there are more than three values to return, 45 | but I have never needed to return more than three values. If you think 46 | you need to return four or more values you probably want to use [a 47 | class](../basics/classes.md) instead. 48 | 49 | For example, instead of this... 50 | 51 | ```python 52 | def get_new_info(username): 53 | print(f"Changing user information of {username}.") 54 | username = input("New username: ") 55 | password = input("New password: ") 56 | fullname = input("Full name: ") 57 | phonenumber = input("Phone number: ") 58 | return (username, password, fullname, phonenumber) 59 | ``` 60 | 61 | ...you could do this: 62 | 63 | ```python 64 | class User: 65 | # you probably want to make many other user related things too, add 66 | # them here 67 | 68 | def change_info(self): 69 | print(f"Changing user information of {self.username}.") 70 | self.username = input("New username: ") 71 | self.password = input("New password: ") 72 | self.fullname = input("Full name: ") 73 | self.phonenumber = input("Phone number: ") 74 | ``` 75 | 76 | ## \*args 77 | 78 | Sometimes you might see code like this: 79 | 80 | ```python 81 | def thing(*args, **kwargs): 82 | ... 83 | ``` 84 | 85 | Functions like this are actually quite easy to understand. Let's make a 86 | function that takes `*args` and prints it. 87 | 88 | ```python 89 | >>> def thing(*args): 90 | ... print("now args is", args) 91 | ... 92 | >>> thing() 93 | now args is () 94 | >>> thing(1, 2, 3) 95 | now args is (1, 2, 3) 96 | >>> 97 | ``` 98 | 99 | So far we have learned that if we want to call a function like 100 | `thing(1, 2, 3)`, then we need to define the arguments when defining the 101 | function like `def thing(a, b, c)`. But `*args` just magically gets 102 | whatever positional arguments the function is given and turns them into 103 | a tuple, and never raises errors. Of course, we could also use whatever 104 | variable name we wanted instead of `args`. 105 | 106 | Our function with nothing but `*args` takes no keyword arguments: 107 | 108 | ```python 109 | >>> thing(a=1) 110 | Traceback (most recent call last): 111 | File "", line 1, in 112 | TypeError: thing() got an unexpected keyword argument 'a' 113 | >>> 114 | ``` 115 | 116 | We can also save our arguments to a variable as a list, and then pass 117 | them to a function by adding a `*`. Actually it doesn't need to be a 118 | list or a tuple, anything [iterable](../basics/loops.md#summary) will 119 | work. 120 | 121 | ```python 122 | >>> stuff = ['hello', 'world', 'test'] 123 | >>> print(*stuff) 124 | hello world test 125 | >>> 126 | ``` 127 | 128 | ## \*\*kwargs 129 | 130 | `**kwargs` is the same thing as `*args`, but with keyword arguments 131 | instead of positional arguments. 132 | 133 | ```python 134 | >>> def thing(**kwargs): 135 | ... print('now kwargs is', kwargs) 136 | ... 137 | >>> thing(a=1, b=2) 138 | now kwargs is {'b': 2, 'a': 1} 139 | >>> thing(1, 2) 140 | Traceback (most recent call last): 141 | File "", line 1, in 142 | TypeError: thing() takes 0 positional arguments but 2 were given 143 | >>> def print_box(message, border): 144 | ... print(border * len(message)) 145 | ... print(message) 146 | ... print(border * len(message)) 147 | ... 148 | >>> kwargs = {'message': "Hello World!", 'border': '*'} 149 | >>> print_box(**kwargs) 150 | ************ 151 | Hello World! 152 | ************ 153 | >>> 154 | ``` 155 | 156 | Sometimes it's handy to capture all arguments our function takes. We can 157 | combine `*args` and `**kwargs` easily: 158 | 159 | ```python 160 | >>> def thing(*args, **kwargs): 161 | ... print("now args is", args, "and kwargs is", kwargs) 162 | ... 163 | >>> thing(1, 2, a=3, b=4) 164 | now args is (1, 2) and kwargs is {'b': 4, 'a': 3} 165 | >>> 166 | ``` 167 | 168 | This is often used for calling a function from another "fake function" 169 | that represents it. We'll find uses for this later. 170 | 171 | ```python 172 | >>> def fake_print(*args, **kwargs): 173 | ... print(*args, **kwargs) 174 | ... 175 | >>> print('this', 'is', 'a', 'test', sep='-') 176 | this-is-a-test 177 | >>> fake_print('this', 'is', 'a', 'test', sep='-') 178 | this-is-a-test 179 | >>> 180 | ``` 181 | 182 | ## Keyword-only arguments 183 | 184 | Let's say that we have a function that moves a file. It probably takes 185 | `source` and `destination` arguments, but it might also take other 186 | arguments that customize how it moves the file. For example, it might 187 | take an `overwrite` argument that makes it remove `destination` before 188 | moving if it exists already or a `backup` argument that makes it do a 189 | backup of the file just in case the moving fails. So our function would 190 | look like this: 191 | 192 | ```python 193 | def move(source, destination, overwrite=False, backup=False): 194 | if overwrite: 195 | print("deleting", destination) 196 | if backup: 197 | print("backing up") 198 | print("moving", source, "to", destination) 199 | ``` 200 | 201 | Then we can move files like this: 202 | 203 | ```python 204 | >>> move('file1.txt', 'file2.txt') 205 | moving file1.txt to file2.txt 206 | >>> move('file1.txt', 'file2.txt', overwrite=True) 207 | deleting file2.txt 208 | moving file1.txt to file2.txt 209 | >>> 210 | ``` 211 | 212 | This works just fine, but if we accidentally give the function three 213 | filenames, bad things will happen: 214 | 215 | ```python 216 | >>> move('file1.txt', 'file2.txt', 'file3.txt') 217 | deleting file2.txt 218 | moving file1.txt to file2.txt 219 | >>> 220 | ``` 221 | 222 | Oh crap, that's not what we wanted at all. We have just lost the 223 | original `file2.txt`! 224 | 225 | The problem was that now `overwrite` was `'file3.txt'`, and the 226 | `if overwrite` part [treated the string as 227 | True](../basics/what-is-true.md) and deleted the file. That's not nice. 228 | 229 | The solution is to change our move function so that `overwrite` and 230 | `backup` are keyword-only: 231 | 232 | ```python 233 | def move(source, destination, *, overwrite=False, backup=False): 234 | ... 235 | ``` 236 | 237 | The `*` between `destination` and `overwrite` means that `overwrite` and 238 | `backup` must be given as keyword arguments. The basic idea is really 239 | simple: now it's impossible to overwrite by doing `move('file1.txt', 240 | 'file2.txt', True)` and the overwrite must be always given like 241 | `overwrite=True`. 242 | 243 | ```python 244 | >>> move('file1.txt', 'file2.txt') 245 | moving file1.txt to file2.txt 246 | >>> move('file1.txt', 'file2.txt', True) 247 | Traceback (most recent call last): 248 | File "", line 1, in 249 | TypeError: move() takes 2 positional arguments but 3 were given 250 | >>> move('file1.txt', 'file2.txt', 'file3.txt') 251 | Traceback (most recent call last): 252 | File "", line 1, in 253 | TypeError: move() takes 2 positional arguments but 3 were given 254 | >>> move('file1.txt', 'file2.txt', overwrite='file3.txt') 255 | deleting file2.txt 256 | moving file1.txt to file2.txt 257 | >>> 258 | ``` 259 | 260 | Doing `overwrite='file3.txt'` doesn't make much sense and it's easy to 261 | notice that something's wrong. 262 | 263 | ## When should we use these things? 264 | 265 | There's nothing wrong with returning a tuple from a function, and you 266 | are free to do that whenever you need it. 267 | 268 | We don't need `*args` and `**kwargs` for most of the functions we write. 269 | When we need to make something that takes whatever arguments it's given 270 | or call a function with arguments that come from a list we need `*args` 271 | and `**kwargs`, and there's no need to avoid them. 272 | 273 | I don't recommend using keyword-only arguments with functions like our 274 | `print_box`. It's easy enough to guess or remember what 275 | `print_box('hello', '-')` does, and there's no need to deny that. It's 276 | much harder to remember what `move('file1.txt', 'file2.txt', True, False)` 277 | does, so using keyword-only arguments makes sense. 278 | 279 | ## Summary 280 | 281 | - If you want to return multiple values from a function you can return 282 | a tuple. 283 | - Defining a function that takes `*args` as an argument makes `args` a 284 | tuple of positional arguments. `**kwargs` is the same thing with 285 | dictionaries and keyword arguments. 286 | - Adding a `*` in a function definition makes all arguments after it 287 | keyword-only. This is useful when using positional arguments would 288 | look implicit, like the True and False in 289 | `move('file1.txt', 'file2.txt', True, False)`. 290 | 291 | *** 292 | 293 | If you have trouble with this tutorial, please 294 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 295 | or [ask for help online](../getting-help.md). 296 | If you like this tutorial, please [give it a 297 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 298 | 299 | You may use this tutorial freely at your own risk. See 300 | [LICENSE](../LICENSE). 301 | 302 | [Previous](datatypes.md) | [Next](magicmethods.md) | 303 | [List of contents](../README.md#advanced) 304 | -------------------------------------------------------------------------------- /basics/docstrings.md: -------------------------------------------------------------------------------- 1 | # Help and Docstrings 2 | 3 | In this tutorial we have used `help()` a few times. It's great and you 4 | can use it as much as you want to. For example, running `help(str)` 5 | displays a nice list of all string methods and explanations of what they 6 | do, and `help(list.extend)` explains what extending something to a list 7 | does. 8 | 9 | You can get help of many other things too. For example: 10 | 11 | ```python 12 | >>> stuff = [] 13 | >>> help(stuff.append) 14 | Help on built-in function append: 15 | 16 | append(object, /) method of builtins.list instance 17 | Append object to the end of the list. 18 | 19 | >>> help(print) 20 | Help on built-in function print in module builtins: 21 | 22 | print(...) 23 | print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) 24 | 25 | Prints the values to a stream, or to sys.stdout by default. 26 | Optional keyword arguments: 27 | ... 28 | ``` 29 | 30 | ## Docstrings 31 | 32 | Let's see what happens if we [define a function](defining-functions.md) 33 | and call `help()` on that. 34 | 35 | ```python 36 | >>> def thing(stuff): 37 | ... return stuff * 2 38 | ... 39 | >>> help(thing) 40 | Help on function thing in module __main__: 41 | 42 | thing(stuff) 43 | >>> 44 | ``` 45 | 46 | That sucked! We have no idea about what it does based on this. All we 47 | know is that it takes a `stuff` argument. 48 | 49 | This is when documentation strings or docstrings come in. All we need to 50 | do is to add a string to the beginning of our function and it will show 51 | up in `help(the_function)`. Like this: 52 | 53 | ```python 54 | >>> def thing(stuff): 55 | ... "hello there" 56 | ... return stuff * 2 57 | ... 58 | >>> help(thing) 59 | Help on function thing in module __main__: 60 | 61 | thing(stuff) 62 | hello there 63 | ``` 64 | 65 | Note that docstrings are not comments. If you add a `# comment` to the 66 | beginning of the function it won't show up in `help()`. 67 | 68 | ## Multi-line strings 69 | 70 | When we did `help(print)`, we got more than one line of help. Maybe we 71 | could do that in our own docstring too? 72 | 73 | ```python 74 | >>> def thing(): 75 | ... "This thing does stuff.\n\nIt always returns None." 76 | ... 77 | >>> help(thing) 78 | Help on function thing in module __main__: 79 | 80 | thing() 81 | This thing does stuff. 82 | 83 | It always returns None. 84 | >>> 85 | ``` 86 | 87 | That's better, but how what if we want to do 5 lines of prints? Our 88 | `"stuff\n\nstuff\nstuff"` thing would be really long and hard to work 89 | with. But Python has multi-line strings too. They work like this: 90 | 91 | ```python 92 | >>> """bla bla bla 93 | ... 94 | ... bla bla 95 | ... bla bla bla""" 96 | 'bla bla bla\n\nbla bla\nbla bla bla' 97 | >>> 98 | ``` 99 | 100 | So we can write documented functions like this: 101 | 102 | ```python 103 | >>> def thing(): 104 | ... """This thing does stuff. 105 | ... 106 | ... It always returns None. 107 | ... """ 108 | ... 109 | >>> help(thing) 110 | Help on function thing in module __main__: 111 | 112 | thing() 113 | This thing does stuff. 114 | 115 | It always returns None. 116 | 117 | >>> 118 | ``` 119 | 120 | It's recommended to always use `"""strings like this"""` for docstrings, 121 | even if the docstring is only one line long. This way it's easy to add 122 | more stuff to it later. 123 | 124 | ## Documenting other stuff 125 | 126 | Docstrings aren't actually limited to functions. You can use them for 127 | documenting [classes](classes.md) and their methods too. For example, 128 | let's make a file like this and save it to `test.py`: 129 | 130 | ```python 131 | """A test module. 132 | 133 | It contains a class and a function. 134 | """ 135 | 136 | 137 | class Thing: 138 | """This is a test class.""" 139 | 140 | def thingy(self): 141 | """This is a test method.""" 142 | print("hello") 143 | 144 | 145 | def do_hello(): 146 | """This is a test function.""" 147 | thing = Thing() 148 | thing.thingy() 149 | ``` 150 | 151 | Then we can import it and call help on it: 152 | 153 | [comment]: # (github screws up syntax highlighting here) 154 | 155 | ``` 156 | >>> import test 157 | >>> help(test) 158 | Help on module testie: 159 | 160 | NAME 161 | testie - A test module. 162 | 163 | DESCRIPTION 164 | It contains a class and a function. 165 | 166 | CLASSES 167 | builtins.object 168 | Thing 169 | 170 | class Thing(builtins.object) 171 | | This is a test class. 172 | | 173 | | Methods defined here: 174 | | 175 | | thingy(self) 176 | | This is a test method. 177 | | 178 | | ---------------------------------------------------------------------- 179 | | Data descriptors defined here: 180 | | 181 | | __dict__ 182 | | dictionary for instance variables (if defined) 183 | | 184 | | __weakref__ 185 | | list of weak references to the object (if defined) 186 | 187 | FUNCTIONS 188 | do_hello() 189 | This is a test function. 190 | 191 | FILE 192 | /home/akuli/testie.py 193 | ``` 194 | 195 | That's pretty cool. We just added docstrings to our code and Python made 196 | this thing out of it. 197 | 198 | You might be wondering what `__weakref__` is. You don't need to care 199 | about it, and I think it would be better if `help()` would hide it. 200 | 201 | ## Popular Docstring Formats 202 | 203 | There are different styles for writing docstrings. If you are contributing to 204 | another Python project, make sure to use the same style as rest of that project 205 | is using. 206 | 207 | If you are starting a new project, then you can use whichever style you 208 | want, but don't "reinvent the wheel"; use an existing style instead instead of 209 | making up your own. Here are some examples of popular docstring styles to choose 210 | from: 211 | 212 | ### Sphinx Style 213 | 214 | [Sphinx](https://www.sphinx-doc.org/en/master/) is the Python documentation tool 215 | that [the official Python documentation](https://docs.python.org/3/) uses. 216 | By default, sphinx expects you to write docstrings like this: 217 | 218 | ```python 219 | class Vehicles: 220 | """ 221 | The Vehicles object contains lots of vehicles. 222 | :param arg: The arg is used for ... 223 | :type arg: str 224 | :ivar arg: This is where we store arg 225 | :vartype arg: str 226 | """ 227 | 228 | def __init__(self, arg): 229 | self.arg = arg 230 | 231 | def cars(self, distance, destination): 232 | """We can't travel a certain distance in vehicles without fuels, so here's the fuels 233 | 234 | :param distance: The amount of distance traveled 235 | :type amount: int 236 | :param bool destinationReached: Should the fuels be refilled to cover required distance? 237 | :raises: :class:`RuntimeError`: Out of fuel 238 | 239 | :returns: A Car mileage 240 | :rtype: Cars 241 | """ 242 | ... 243 | ``` 244 | 245 | ### Google Style 246 | 247 | Google Style is meant to be easier to read and use without a tool like sphinx. 248 | Sphinx can be configured to use that with 249 | [sphinx.ext.napoleon](https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html). 250 | 251 | ```python 252 | class Vehicles: 253 | """ 254 | The Vehicles object contains lots of vehicles. 255 | 256 | Args: 257 | arg (str): The arg is used for... 258 | 259 | Attributes: 260 | arg (str): This is where we store arg. 261 | """ 262 | 263 | def __init__(self, arg): 264 | self.arg = arg 265 | 266 | def cars(self, distance, destination): 267 | """We can't travel distance in vehicles without fuels, so here is the fuels 268 | 269 | Args: 270 | distance (int): The amount of distance traveled 271 | destination (bool): Should the fuels refilled to cover the distance? 272 | 273 | Raises: 274 | RuntimeError: Out of fuel 275 | 276 | Returns: 277 | cars: A car mileage 278 | """ 279 | ... 280 | 281 | ``` 282 | 283 | ### Numpy Style 284 | 285 | [Numpy](https://numpy.org/) is a large and popular Python library, 286 | and numpy developers have their own docstring style. 287 | 288 | ```python 289 | class Vehicles: 290 | """ 291 | The Vehicles object contains lots of vehicles. 292 | 293 | Parameters 294 | ---------- 295 | arg : str 296 | The arg is used for ... 297 | *args 298 | The variable arguments are used for ... 299 | **kwargs 300 | The keyword arguments are used for ... 301 | 302 | Attributes 303 | ---------- 304 | arg : str 305 | This is where we store arg. 306 | """ 307 | 308 | def __init__(self, arg): 309 | self.arg = arg 310 | 311 | def cars(self, distance, destination): 312 | """We can't travel distance in vehicles without fuels, so here is the fuels 313 | 314 | Parameters 315 | ---------- 316 | distance : int 317 | The amount of distance traveled 318 | destination : bool 319 | Should the fuels refilled to cover the distance? 320 | 321 | Raises 322 | ------ 323 | RuntimeError 324 | Out of fuel 325 | 326 | Returns 327 | ------- 328 | cars 329 | A car mileage 330 | """ 331 | pass 332 | ``` 333 | 334 | ## When should we use docstrings? 335 | 336 | I recommend using docstrings when writing code that other people will import. 337 | The `help()` function is awesome, so it's good to make sure it's actually helpful. 338 | 339 | If your code is not meant to be imported, docstrings are usually a good 340 | idea anyway. Other people reading your code will understand what it's 341 | doing without having to read through all of the code. 342 | 343 | ## Summary 344 | 345 | - `help()` is awesome. 346 | - A `"""triple-quoted string"""` string in the beginning of a function, 347 | class or file is a docstring. It shows up in `help()`. 348 | - Docstrings are not comments. 349 | - Usually it's a good idea to add docstrings everywhere. 350 | 351 | *** 352 | 353 | If you have trouble with this tutorial, please 354 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 355 | or [ask for help online](../getting-help.md). 356 | If you like this tutorial, please [give it a 357 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 358 | 359 | You may use this tutorial freely at your own risk. See 360 | [LICENSE](../LICENSE). 361 | 362 | [Previous](classes.md) | [Next](../advanced/datatypes.md) | 363 | [List of contents](../README.md#basics) 364 | -------------------------------------------------------------------------------- /basics/dicts.md: -------------------------------------------------------------------------------- 1 | # Dictionaries 2 | 3 | Now we know how [lists and tuples](lists-and-tuples.md) work and how 4 | to [for loop](loops.md#for-loops) over them. If we make some kind of 5 | program that needs to keep track of people's names and favorite pets, 6 | we can use a list for that: 7 | 8 | ```python 9 | names_and_pets = [ 10 | ('horusr', 'cats'), 11 | ('caisa64', 'cats and dogs'), 12 | ('__Myst__', 'cats'), 13 | ] 14 | ``` 15 | 16 | Then to check if cats are horusr's favorite pets we can do 17 | `('horusr', 'cats') in names_and_pets`. Or we can add new people's 18 | favorite pets easily by appending new `(name, pets)` tuples to the list. 19 | 20 | But what if we need to check if we know anything about someone's 21 | favorite pets? `'caisa64' in names_and_pets` is always False because the 22 | pet list consists of `(name, pets)` pairs instead of just names, so we 23 | need to for loop over the whole pet list: 24 | 25 | ```python 26 | found_caisa64 = False 27 | for pair in names_and_pets: 28 | if pair[0] == 'caisa64': 29 | found_caisa64 = True 30 | break 31 | if found_caisa64: 32 | # do something 33 | ``` 34 | 35 | Or what if we need to find out what caisa64's favorite pets are? That 36 | also requires going through the whole list. 37 | 38 | ```python 39 | pets = None 40 | for pair in names_and_pets: 41 | if pair[0] == 'caisa64': 42 | pets = pair[1] 43 | break 44 | # make sure pets is not None and do something with it 45 | ``` 46 | 47 | As you can see, a list of `(name, pets)` pairs is not an ideal 48 | way to store names and favorite pets. 49 | 50 | ## What are dictionaries? 51 | 52 | A better way to store information about favorite pets might be a 53 | dictionary: 54 | 55 | ```python 56 | favorite_pets = { 57 | 'horusr': 'cats', 58 | 'caisa64': 'cats and dogs', 59 | '__Myst__': 'cats', 60 | } 61 | ``` 62 | 63 | Here `'horusr'` and `'caisa64'` are **keys** in the dictionary, and 64 | `'cats'` and `'cats and dogs'` are their **values**. Dictionaries are 65 | often named by their values. This dictionary has favorite pets as its 66 | values so I named the variable `favorite_pets`. 67 | 68 | There are a few big differences between dictionaries and lists of pairs: 69 | 70 | - Dictionaries are not ordered. There are **no guarantees** about which 71 | order the `name: pets` pairs appear in when we do something 72 | with the dictionary. 73 | - Checking if a key is in the dictionary is simple and fast. We don't 74 | need to for loop through the whole dictionary. 75 | - Getting the value of a key is also simple and fast. 76 | - We can't have the same key in the dictionary multiple times, but 77 | multiple different keys can have the same value. This means that 78 | **multiple people can't have the same name, but they can have the 79 | same favorite pets**. 80 | 81 | But wait... this is a lot like variables are! Our variables are not 82 | ordered, getting a value of a variable is fast and easy and we can't 83 | have multiple variables with the same name. 84 | 85 | Variables are actually stored in a dictionary. We can get that 86 | dictionary with the globals function. In this dictionary, keys are 87 | variable names and values are what our variables point to. 88 | 89 | ```python 90 | >>> globals() 91 | {'names_and_pets': [('horusr', 'cats'), 92 | ('caisa64', 'cats and dogs'), 93 | ('__Myst__', 'cats')], 94 | 'favorite_pets': {'__Myst__': 'cats', 95 | 'caisa64': 'cats and dogs', 96 | 'horusr': 'cats'}, 97 | ...many other things we don't need to care about... 98 | } 99 | >>> 100 | ``` 101 | 102 | So if you have trouble remembering how dictionaries work just compare 103 | them to variables. A dictionary is a perfect way to store these names 104 | and favorite pets. We don't care about which order the names and pets 105 | were added in, it's impossible to add the same name multiple times and 106 | getting someone's favorite pets is easy. 107 | 108 | ## What can we do with dictionaries? 109 | 110 | Dictionaries have some similarities with lists. For example, both 111 | lists and dictionaries have a length. 112 | 113 | ```python 114 | >>> len(names_and_pets) # contains three elements 115 | 3 116 | >>> len(favorite_pets) # contains three key:value pairs 117 | 3 118 | >>> 119 | ``` 120 | 121 | We can get a value of a key with `the_dict[key]`. This is a lot easier 122 | and faster than for-looping over a list of pairs. 123 | 124 | ```python 125 | >>> favorite_pets['caisa64'] 126 | 'cats and dogs' 127 | >>> favorite_pets['__Myst__'] 128 | 'cats' 129 | >>> 130 | ``` 131 | 132 | Trying to get the value of a non-existing key gives us an error. 133 | 134 | ```python 135 | >>> favorite_pets['Akuli'] 136 | Traceback (most recent call last): 137 | File "", line 1, in 138 | KeyError: 'Akuli' 139 | >>> 140 | ``` 141 | 142 | But we can add new `key: value` pairs or change the values of existing 143 | keys by doing `the_dict[key] = value`. 144 | 145 | ```python 146 | >>> favorite_pets['Akuli'] = 'penguins' 147 | >>> favorite_pets['Akuli'] 148 | 'penguins' 149 | >>> favorite_pets['Akuli'] = 'dogs' 150 | >>> favorite_pets['Akuli'] 151 | 'dogs' 152 | >>> favorite_pets 153 | {'__Myst__': 'cats', 154 | 'Akuli': 'dogs', 155 | 'horusr': 'cats', 156 | 'caisa64': 'cats and dogs'} 157 | >>> 158 | ``` 159 | 160 | For looping over a dictionary gets its keys, and checking if something 161 | is in the dictionary checks if the dictionary has a key like that. This 162 | can be confusing at first but you'll get used to this. 163 | 164 | ```python 165 | >>> 'Akuli' in favorite_pets 166 | True 167 | >>> 'dogs' in favorite_pets 168 | False 169 | >>> for name in favorite_pets: 170 | ... print(name) 171 | ... 172 | caisa64 173 | Akuli 174 | __Myst__ 175 | horusr 176 | >>> 177 | ``` 178 | 179 | Dictionaries have a values method that we can use if we want to do 180 | something with the values: 181 | 182 | ```python 183 | >>> favorite_pets.values() 184 | dict_values(['dogs', 'cats', 'cats and dogs', 'cats']) 185 | >>> 186 | ``` 187 | 188 | The values method returned a `dict_values` object. Things like this 189 | behave a lot like lists and usually we don't need to convert them to 190 | lists. 191 | 192 | ```python 193 | >>> for pets in favorite_pets.values(): 194 | ... print(pets) 195 | ... 196 | dogs 197 | cats 198 | cats and dogs 199 | cats 200 | >>> 201 | ``` 202 | 203 | We can do things like `list(favorite_pets.values())` if we need a real 204 | list for some reason, but doing that can slow down our program if the 205 | dictionary is big. There's also a keys method, but usually we don't need 206 | it because the dictionary itself behaves a lot like a list of keys. 207 | 208 | If we need both keys and values we can use the items method with the 209 | `for first, second in thing` trick. 210 | 211 | ```python 212 | >>> favorite_pets.items() 213 | dict_items([('Akuli', 'dogs'), 214 | ('__Myst__', 'cats'), 215 | ('caisa64', 'cats and dogs'), 216 | ('horusr', 'cats')]) 217 | >>> for name, pets in favorite_pets.items(): 218 | ... print("{} are {}'s favorite pets".format(pets, name)) 219 | ... 220 | dogs are Akuli's favorite pets 221 | cats are __Myst__'s favorite pets 222 | cats and dogs are caisa64's favorite pets 223 | cats are horusr's favorite pets 224 | >>> 225 | ``` 226 | 227 | This is also useful for checking if the dictionary has a `key: value` 228 | pair. 229 | 230 | ```python 231 | >>> ('horusr', 'cats') in favorite_pets.items() 232 | True 233 | >>> ('horusr', 'dogs') in favorite_pets.items() 234 | False 235 | >>> 236 | ``` 237 | 238 | ## Limitations 239 | 240 | Sometimes it might be handy to use lists as dictionary keys, but it 241 | just doesn't work. I'm not going to explain why Python doesn't allow 242 | this because usually we don't need to worry about that. 243 | 244 | ```python 245 | >>> stuff = {['a', 'b']: 'c', ['d', 'e']: 'f'} 246 | Traceback (most recent call last): 247 | File "", line 1, in 248 | TypeError: unhashable type: 'list' 249 | >>> 250 | ``` 251 | 252 | On the other hand, tuples work just fine: 253 | 254 | ```python 255 | >>> stuff = {('a', 'b'): 'c', ('d', 'e'): 'f'} 256 | >>> stuff 257 | {('a', 'b'): 'c', ('d', 'e'): 'f'} 258 | >>> 259 | ``` 260 | 261 | The values of a dictionary can be anything. 262 | 263 | ```python 264 | >>> stuff = {'a': [1, 2, 3], 'b': [4, 5, 6]} 265 | >>> stuff 266 | {'a': [1, 2, 3], 'b': [4, 5, 6]} 267 | >>> 268 | ``` 269 | 270 | ## Summary 271 | 272 | - Dictionaries consist of `key: value` pairs. 273 | - Variables are stored in a dictionary with their names as keys, so 274 | dictionaries behave a lot like variables: 275 | - Dictionaries are not ordered. 276 | - Setting or getting the value of a key is simple and fast. 277 | - Dictionaries can't contain the same key more than once. 278 | - For-looping over a dictionary loops over its keys, and checking if 279 | something is in the dictionary checks if the dictionary has a key 280 | like that. The `values()` and `items()` methods return things that 281 | behave like lists of values or `(key, value)` pairs instead. 282 | 283 | ## Examples 284 | 285 | This program counts how many times words appear in a sentence. 286 | `sentence.split()` creates a list of words in the sentence, see 287 | `help(str.split)` for more info. 288 | 289 | ```python 290 | sentence = input("Enter a sentence: ") 291 | 292 | counts = {} # {word: count, ...} 293 | for word in sentence.split(): 294 | if word in counts: 295 | # we have seen this word before 296 | counts[word] += 1 297 | else: 298 | # this is the first time this word occurs 299 | counts[word] = 1 300 | 301 | print() # display an empty line 302 | for word, count in counts.items(): 303 | if count == 1: 304 | # "1 times" looks weird 305 | print(word, "appears once in the sentence") 306 | else: 307 | print(word, "appears", count, "times in the sentence") 308 | ``` 309 | 310 | Running the program might look like this: 311 | 312 | Enter a sentence: this is a test and this is quite long because this is a test 313 | 314 | is appears 3 times in the sentence 315 | long appears once in the sentence 316 | a appears 2 times in the sentence 317 | because appears once in the sentence 318 | this appears 3 times in the sentence 319 | quite appears once in the sentence 320 | and appears once in the sentence 321 | test appears 2 times in the sentence 322 | 323 | **TODO:** Exercises. 324 | 325 | *** 326 | 327 | If you have trouble with this tutorial, please 328 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 329 | or [ask for help online](../getting-help.md). 330 | If you like this tutorial, please [give it a 331 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 332 | 333 | You may use this tutorial freely at your own risk. See 334 | [LICENSE](../LICENSE). 335 | 336 | [Previous](zip-and-enumerate.md) | [Next](defining-functions.md) | 337 | [List of contents](../README.md#basics) 338 | -------------------------------------------------------------------------------- /make-html.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This is free and unencumbered software released into the public 4 | # domain. 5 | 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a 8 | # compiled binary, for any purpose, commercial or non-commercial, and 9 | # by any means. 10 | 11 | # In jurisdictions that recognize copyright laws, the author or 12 | # authors of this software dedicate any and all copyright interest in 13 | # the software to the public domain. We make this dedication for the 14 | # benefit of the public at large and to the detriment of our heirs 15 | # and successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to 17 | # this software under copyright law. 18 | 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 23 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 24 | # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | # For more information, please refer to 28 | 29 | """Create HTML files of the tutorial.""" 30 | 31 | import argparse 32 | import os 33 | import platform 34 | import posixpath 35 | import shutil 36 | import sys 37 | import textwrap 38 | import webbrowser 39 | 40 | if platform.system() == 'Windows': 41 | python = 'py' 42 | else: 43 | python = 'python3' 44 | 45 | try: 46 | import mistune 47 | except ImportError: 48 | print("mistune isn't installed.", file=sys.stderr) 49 | print("You can install it by running this command on a terminal or ") 50 | print("command prompt:") 51 | print() 52 | print(" %s -m pip install mistune" % python) 53 | sys.exit(1) 54 | 55 | try: 56 | import pygments.formatters 57 | import pygments.lexers 58 | import pygments.style 59 | import pygments.styles 60 | import pygments.token 61 | except ImportError: 62 | # we can work without pygments, but we won't get colors 63 | pygments = None 64 | 65 | import common 66 | 67 | 68 | if pygments is not None: 69 | class TutorialStyle(pygments.style.Style): 70 | background_color = '#111111' 71 | styles = { 72 | pygments.token.Comment: 'italic #336666', 73 | pygments.token.Keyword: 'bold #6699cc', 74 | pygments.token.Name.Builtin: '#9966ff', 75 | pygments.token.String: '#ffff33', 76 | pygments.token.Name.Exception: 'bold #ff0000', 77 | } 78 | 79 | 80 | HTML_TEMPLATE = """\ 81 | 82 | 83 | 84 | 85 | {title} 86 | 87 | 88 | 89 | {body} 90 | 91 | 92 | """ 93 | 94 | 95 | def mkdir_and_open(filename, mode): 96 | """Like open(), but make directories as needed.""" 97 | directory = os.path.dirname(filename) 98 | os.makedirs(directory, exist_ok=True) 99 | return open(filename, mode) 100 | 101 | 102 | def fix_filename(filename): 103 | renames = [('README.md', 'index.html'), 104 | ('LICENSE', 'LICENSE.txt')] 105 | for before, after in renames: 106 | if posixpath.basename(filename) == before: 107 | # BEFORE -> AFTER 108 | # some/place/BEFORE -> some/place/AFTER 109 | return filename[:-len(before)] + after 110 | if filename.endswith('.md'): 111 | filename = filename[:-3] + '.html' 112 | return filename 113 | 114 | 115 | class TutorialRenderer(mistune.HTMLRenderer): 116 | 117 | def __init__(self, pygments_style): 118 | super().__init__() 119 | self.pygments_style = pygments_style 120 | self.title = None # will be set by header() 121 | 122 | def header(self, text, level, raw): 123 | """Create a header that is also a link and a # link target.""" 124 | # "# raw" 125 | if level == 1: 126 | self.title = text 127 | target = common.header_link(raw) 128 | content = super().header(text, level, raw) 129 | return '{1}'.format(target, content) 130 | 131 | def link(self, link, title, text): 132 | """Return a link that points to the correct file.""" 133 | # "[text](link)" 134 | if link.startswith('#'): 135 | # it's like "#title", no need to do anything 136 | pass 137 | elif '#' in link: 138 | # it's like "some-file#title", we need to fix some-file 139 | before, after = link.split('#', 1) 140 | link = fix_filename(before) + '#' + after 141 | else: 142 | # it's like "some-file" 143 | link = fix_filename(link) 144 | return super().link(link, title, text) 145 | 146 | def block_code(self, code, lang=None): 147 | """Highlight Python code blocks with Pygments if it's installed.""" 148 | if lang == 'python' and pygments is not None: 149 | # we can highlight it 150 | if code.startswith('>>> '): 151 | lexer = pygments.lexers.PythonConsoleLexer(python3=True) 152 | else: 153 | lexer = pygments.lexers.Python3Lexer() 154 | formatter = pygments.formatters.HtmlFormatter( 155 | style=self.pygments_style, noclasses=True) 156 | return pygments.highlight(code, lexer, formatter) 157 | 158 | elif lang == 'diff': 159 | # http://stackoverflow.com/a/39413824 160 | result = [] 161 | for line in code.split('\n'): 162 | line = line.strip() 163 | if not line: 164 | continue 165 | 166 | if line.startswith('+'): 167 | result.append('

%s

' 168 | % line.strip('+')) 169 | elif line.startswith('-'): 170 | result.append('

%s

' 171 | % line.strip('-')) 172 | else: 173 | result.append('

%s

' % line) 174 | 175 | return '\n'.join(result) 176 | 177 | else: 178 | # we can't highlight it 179 | return super().block_code(code, lang) 180 | 181 | def image(self, src, title, text): 182 | """Return an image inside a link.""" 183 | result = super().image(src, title, text) 184 | return self.link(src, title, result) 185 | 186 | def table(self, header, body): 187 | """Return a table with a border.""" 188 | result = super().table(header, body) 189 | return result.replace('', '
', 1) 190 | 191 | 192 | def wrap_text(text): 193 | """Like textwrap.fill, but respects newlines.""" 194 | result = [] 195 | for part in text.split('\n'): 196 | result.append(textwrap.fill(part)) 197 | return '\n'.join(result) 198 | 199 | 200 | def main(): 201 | desc = ("Create HTML files of the tutorial.\n\n" 202 | "The files have light text on a dark background by " 203 | "default, and you can edit html-style.css to change that.") 204 | if pygments is not None: 205 | desc += ( 206 | " Editing the style file doesn't change the colors of the " 207 | "code examples, but you can use the --pygments-style " 208 | "option. Search for 'pygments style gallery' online or see " 209 | "https://help.farbox.com/pygments.html to get an idea of " 210 | "what different styles look like.") 211 | 212 | parser = argparse.ArgumentParser( 213 | description=wrap_text(desc), 214 | formatter_class=argparse.RawDescriptionHelpFormatter) 215 | parser.add_argument( 216 | '-o', '--outdir', default='html', 217 | help="write the HTML files here, defaults to %(default)r") 218 | if pygments is not None: 219 | parser.add_argument( 220 | '--pygments-style', metavar='STYLE', default=TutorialStyle, 221 | choices=list(pygments.styles.get_all_styles()), 222 | help=("the Pygments color style (see above), " 223 | "defaults to a custom style")) 224 | args = parser.parse_args() 225 | 226 | if pygments is None: 227 | print("Pygments isn't installed. You can install it like this:") 228 | print() 229 | print(" %s -m pip install pygments" % python) 230 | print() 231 | print("You can also continue without Pygments, but the code examples") 232 | print("will not be colored.") 233 | if not common.askyesno("Continue without pygments?"): 234 | print("Interrupt.") 235 | return 236 | args.pygments_style = None 237 | 238 | if os.path.exists(args.outdir): 239 | if not common.askyesno("%s exists. Do you want to remove it?" 240 | % args.outdir): 241 | print("Interrupt.") 242 | return 243 | if os.path.isdir(args.outdir): 244 | shutil.rmtree(args.outdir) 245 | else: 246 | os.remove(args.outdir) 247 | 248 | print("Generating HTML files...") 249 | for markdownfile in common.get_markdown_files(): 250 | fixed_file = fix_filename(markdownfile) 251 | htmlfile = posixpath.join(args.outdir, fixed_file) 252 | print(' %-30.30s --> %-30.30s' % (markdownfile, htmlfile), end='\r') 253 | 254 | with open(markdownfile, 'r') as f: 255 | markdown = f.read() 256 | renderer = TutorialRenderer(args.pygments_style) 257 | body = mistune.markdown(markdown, renderer=renderer) 258 | stylefile = posixpath.relpath( 259 | 'style.css', posixpath.dirname(fixed_file)) 260 | 261 | html = HTML_TEMPLATE.format( 262 | title=renderer.title, 263 | body=body, 264 | stylefile=stylefile, 265 | ) 266 | with mkdir_and_open(htmlfile, 'w') as f: 267 | print(html, file=f) 268 | print() 269 | 270 | print("Copying other files...") 271 | shutil.copytree('images', os.path.join(args.outdir, 'images')) 272 | shutil.copy('LICENSE', os.path.join(args.outdir, 'LICENSE.txt')) 273 | shutil.copy('html-style.css', os.path.join(args.outdir, 'style.css')) 274 | 275 | print("\n*********************\n") 276 | print("Ready! The files are in %r." % args.outdir) 277 | print("You can go there and double-click index.html to read the tutorial.") 278 | print() 279 | if common.askyesno("Do you want to view the tutorial now?", default=False): 280 | print("Opening the tutorial...") 281 | webbrowser.open(os.path.join(args.outdir, 'index.html')) 282 | 283 | 284 | if __name__ == '__main__': 285 | main() 286 | -------------------------------------------------------------------------------- /basics/lists-and-tuples.md: -------------------------------------------------------------------------------- 1 | # Lists and tuples 2 | 3 | ## Why should we use lists? 4 | 5 | Sometimes we may end up doing something like this. 6 | 7 | ```python 8 | name1 = 'wub_wub' 9 | name2 = 'theelous3' 10 | name3 = 'RubyPinch' 11 | name4 = 'go|dfish' 12 | name5 = 'Nitori' 13 | 14 | name = input("Enter your name: ") 15 | if name == name1 or name == name2 or name == name3 or name == name4 or name == name5: 16 | print("I know you!") 17 | else: 18 | print("Sorry, I don't know who you are :(") 19 | ``` 20 | 21 | This code works just fine, but there's a problem. The name check 22 | is repetitive, and adding a new name requires adding even more 23 | repetitive, boring checks. 24 | 25 | ## Our first list 26 | 27 | Instead of adding a new variable for each name it might be 28 | better to store all names in one variable. This means that our 29 | one variable needs to point to multiple values. An easy way to 30 | do this is using a list: 31 | 32 | ```python 33 | names = ['wub_wub', 'theelous3', 'Nitori', 'RubyPinch', 'go|dfish'] 34 | ``` 35 | 36 | Here the `names` variable points to a list, which then points to 37 | strings, like this: 38 | 39 | ![List of names.](../images/people.png) 40 | 41 | ## What can we do with lists? 42 | 43 | Let's open the `>>>` prompt and create a name list. 44 | 45 | ```python 46 | >>> names = ['wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori'] 47 | >>> names 48 | ['wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori'] 49 | >>> 50 | ``` 51 | 52 | There's many things [we can do with strings](handy-stuff-strings.md), 53 | and some of these things also work with lists. 54 | 55 | ```python 56 | >>> len(names) # len is short for length, we have 5 names 57 | 5 58 | >>> names + ['Akuli'] # create a new list with me in it 59 | ['wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori', 'Akuli'] 60 | >>> ['theelous3', 'RubyPinch'] * 2 # repeating 61 | ['theelous3', 'RubyPinch', 'theelous3', 'RubyPinch'] 62 | >>> 63 | ``` 64 | 65 | With strings indexing and slicing both returned a string, but 66 | with lists we get a new list when we're slicing and an element 67 | from the list if we're indexing. 68 | 69 | ```python 70 | >>> names[:2] # first two names 71 | ['wub_wub', 'theelous3'] 72 | >>> names[0] # the first name 73 | 'wub_wub' 74 | >>> 75 | ``` 76 | 77 | If we want to check if the program knows a name all we need to 78 | do is to use the `in` keyword. 79 | 80 | ```python 81 | >>> 'lol' in names 82 | False 83 | >>> 'RubyPinch' in names 84 | True 85 | >>> 86 | ``` 87 | 88 | We can't use this for checking if a list of names is a part of 89 | our name list. 90 | 91 | ```python 92 | >>> ['RubyPinch', 'go|dfish'] in names 93 | False 94 | >>> ['RubyPinch'] in names 95 | False 96 | >>> 97 | ``` 98 | 99 | Lists have a few [useful 100 | methods](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists). 101 | Some of the most commonly used ones are append, extend and remove. 102 | `append` adds an item to the end of a list, `extend` adds 103 | multiple items from another list and `remove` removes an item. 104 | 105 | ```python 106 | >>> names 107 | ['wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori'] 108 | >>> names.remove('theelous3') # sorry theelous3 109 | >>> names.remove('go|dfish') # and sorry go|dfish 110 | >>> names 111 | ['wub_wub', 'RubyPinch', 'Nitori'] 112 | >>> names.append('Akuli') # let's add me here 113 | >>> names 114 | ['wub_wub', 'RubyPinch', 'Nitori', 'Akuli'] 115 | >>> names.extend(['go|dfish', 'theelous3']) # wb guys 116 | >>> names 117 | ['wub_wub', 'RubyPinch', 'Nitori', 'Akuli', 'go|dfish', 'theelous3'] 118 | >>> 119 | ``` 120 | 121 | Note that `remove` removes only the first match it finds. 122 | 123 | ```python 124 | >>> names = ['theelous3', 'go|dfish', 'theelous3'] 125 | >>> names.remove('theelous3') 126 | >>> names # the second theelous3 is still there! 127 | ['go|dfish', 'theelous3'] 128 | >>> 129 | ``` 130 | 131 | If we need to remove all matching items we can use a simple while loop. 132 | We'll talk more about loops [in the next chapter](loops.md). 133 | 134 | ```python 135 | >>> names = ['theelous3', 'go|dfish', 'theelous3'] 136 | >>> while 'theelous3' in names: 137 | ... names.remove('theelous3') 138 | ... 139 | >>> names 140 | ['go|dfish'] 141 | >>> 142 | ``` 143 | 144 | Another useful thing about lists is **list comprehension**. 145 | It's a handy way to construct a list in single line. It often makes code cleaner, shorter and easier to read. 146 | 147 | ```python 148 | >>> numbers = [1,2,3,4,5] 149 | >>> numbers_squared = [number ** 2 for number in numbers] 150 | >>> numbers_squared 151 | [1, 4, 9, 16, 25] 152 | >>> 153 | ``` 154 | 155 | Without a list comprehension, doing the same thing looks like this: 156 | 157 | ```python 158 | >>> numbers = [1,2,3,4,5] 159 | >>> numbers_squared = [] 160 | >>> for number in numbers: 161 | ... numbers_squared.append(number**2) 162 | >>> numbers_squared 163 | [1, 4, 9, 16, 25] 164 | >>> 165 | ``` 166 | 167 | We can also use slicing and indexing to change the content: 168 | 169 | ```python 170 | >>> names = ['theelous3', 'LOL', 'RubyPinch', 'go|dfish', 'Nitori'] 171 | >>> names[1] = 'wub_wub' # replace LOL with wub_wub 172 | >>> names 173 | ['theelous3', 'wub_wub', 'RubyPinch', 'go|dfish', 'Nitori'] 174 | >>> 175 | ``` 176 | 177 | As you can see, **list can be changed in-place**. In other 178 | words, they are **mutable**. Integers, floats, strings and many 179 | other built-in types can't, so they are **immutable**. 180 | 181 | With [strings](handy-stuff-strings.md) we did something to them 182 | and then set the result back to the same variable, like 183 | `message = message.strip()`. This just doesn't work right with 184 | most mutable things because they're designed to be changed in-place. 185 | 186 | ```python 187 | >>> names = names.remove('Akuli') 188 | >>> print(names) # now it's None! 189 | None 190 | >>> 191 | ``` 192 | 193 | This is the same thing that happened way back when [we assigned 194 | print's return value to a variable](using-functions.md#return-values). 195 | 196 | ## What is what? 197 | 198 | After working with lists a while you'll find out that they 199 | behave like this: 200 | 201 | ```python 202 | >>> a = [1, 2, 3] 203 | >>> b = a 204 | >>> b.append(4) 205 | >>> a # this changed also! 206 | [1, 2, 3, 4] 207 | >>> 208 | ``` 209 | 210 | This can be confusing at first, but it's actually easy to 211 | explain. The problem with this code example is the `b = a` 212 | line. If we draw a picture of the variables it looks like this: 213 | 214 | ![Same list.](../images/samelist.png) 215 | 216 | This is when the `is` keyword comes in. It can be used to 217 | check if two variables point to the **same** thing. 218 | 219 | ```python 220 | >>> a is b 221 | True 222 | >>> 223 | ``` 224 | 225 | Typing `[]` creates a **new** list every time. 226 | 227 | ```python 228 | >>> [] is [] 229 | False 230 | >>> [1, 2, 3] is [1, 2, 3] 231 | False 232 | >>> 233 | ``` 234 | 235 | If we need **a new list with similar content** we can use the 236 | `copy` method. 237 | 238 | ```python 239 | >>> a = [1, 2, 3] 240 | >>> b = a.copy() 241 | >>> b is a 242 | False 243 | >>> b.append(4) 244 | >>> b 245 | [1, 2, 3, 4] 246 | >>> a 247 | [1, 2, 3] 248 | >>> 249 | ``` 250 | 251 | If we draw a picture of our variables in this example it looks 252 | like this: 253 | 254 | ![Different lists.](../images/differentlist.png) 255 | 256 | ## Tuples 257 | 258 | Tuples are a lot like lists, but they're immutable so they 259 | can't be changed in-place. We create them like lists, but 260 | with `()` instead of `[]`. 261 | 262 | ```python 263 | >>> thing = (1, 2, 3) 264 | >>> thing 265 | (1, 2, 3) 266 | >>> thing = () 267 | >>> thing 268 | () 269 | >>> 270 | ``` 271 | 272 | If we need to create a tuple that contains only one item we 273 | need to use `(item,)` instead of `(item)` because `(item)` is 274 | used in places like `(1 + 2) * 3`. 275 | 276 | ```python 277 | >>> (3) 278 | 3 279 | >>> (3,) 280 | (3,) 281 | >>> (1 + 2) * 3 282 | 9 283 | >>> (1 + 2,) * 3 284 | (3, 3, 3) 285 | >>> 286 | ``` 287 | 288 | It's also possible to create tuples by just separating things with 289 | commas and adding no parentheses. Personally I don't like this feature, 290 | but some people like to do it this way. 291 | 292 | ```python 293 | >>> 1, 2, 3 294 | (1, 2, 3) 295 | >>> 'hello', 296 | ('hello',) 297 | >>> 298 | ``` 299 | 300 | Tuples don't have methods like append, extend and remove 301 | because they can't change themselves in-place. 302 | 303 | ```python 304 | >>> stuff = (1, 2, 3) 305 | >>> stuff.append(4) 306 | Traceback (most recent call last): 307 | File "", line 1, in 308 | AttributeError: 'tuple' object has no attribute 'append' 309 | >>> 310 | ``` 311 | 312 | So, why the heck would we use tuples instead of lists? There are 313 | some cases when we don't want mutability, but there are also 314 | cases when Python programmers just like to use tuples. If you 315 | want to know more about this you can read [Ned Batchelder's blog 316 | post about this](http://nedbatchelder.com/blog/201608/lists_vs_tuples.html). 317 | 318 | ## Summary 319 | 320 | - Lists are a way to store multiple values in one variable. 321 | - Lists can be changed in-place and they have methods that change them 322 | in-place, like append, extend and remove. 323 | - Slicing lists returns a **new** list, and indexing them returns an 324 | item from them. 325 | - `thing = another_thing` does not create a copy of `another_thing`. 326 | - Tuples are like lists, but they can't be changed in-place. They're 327 | also used in different places. 328 | 329 | ## Examples 330 | 331 | Here's the same program we had in the beginning of this tutorial, but 332 | using a list: 333 | 334 | ```python 335 | namelist = ['wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori'] 336 | 337 | name = input("Enter your name: ") 338 | if name in namelist: 339 | print("I know you!") 340 | else: 341 | print("Sorry, I don't know who you are :(") 342 | ``` 343 | 344 | ## Exercises 345 | 346 | 1. Fix this program: 347 | 348 | ```python 349 | namelist = ('wub_wub', 'RubyPinch', 'go|dfish', 'Nitori') 350 | namelist.append('pb122') 351 | if 'pb122' in namelist: 352 | print("Now I know pb122!") 353 | ``` 354 | 355 | 2. Fix this program. 356 | 357 | ```python 358 | print("Hello!") 359 | name = input("Enter your name: "), 360 | print("Your name is " + name + ".") 361 | ``` 362 | 363 | 3. Fix this program. 364 | 365 | ```python 366 | namelist = ['wub_wub', 'RubyPinch', 'go|dfish', 'Nitori'] 367 | namelist = namelist.extend('theelous3') 368 | if input("Enter your name: ") in namelist: 369 | print("I know you!") 370 | else: 371 | print("I don't know you.") 372 | ``` 373 | 374 | The answers are [here](answers.md#lists-and-tuples). 375 | 376 | *** 377 | 378 | If you have trouble with this tutorial, please 379 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 380 | or [ask for help online](../getting-help.md). 381 | If you like this tutorial, please [give it a 382 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 383 | 384 | You may use this tutorial freely at your own risk. See 385 | [LICENSE](../LICENSE). 386 | 387 | [Previous](handy-stuff-strings.md) | [Next](loops.md) | 388 | [List of contents](../README.md#basics) 389 | -------------------------------------------------------------------------------- /advanced/datatypes.md: -------------------------------------------------------------------------------- 1 | # Handy data types in the standard library 2 | 3 | [comment]: # (this doesn't explain how dict.setdefault and collections.defaultdict) 4 | [comment]: # (work because they're not as simple as the things that are here and i) 5 | [comment]: # (don't actually use them that much) 6 | 7 | Now we know how to use lists, tuples and dictionaries. They are commonly 8 | used data types in Python, and there's nothing wrong with them. In this 9 | chapter we'll learn more data types that make some things easier. You 10 | can always do everything with lists and dictionaries, but these data 11 | types can do a lot of the work for you. 12 | 13 | > If it looks like a duck and quacks like a duck, it must be a duck. 14 | 15 | Many things in this tutorial are not really something but they behave 16 | like something. For example, we'll learn about many classes that behave 17 | like dictionaries. They are not dictionaries, but we can use them just 18 | like if they were dictionaries. This programming style is known as 19 | **duck-typing**. 20 | 21 | ## Sets 22 | 23 | Let's say we have a program that keeps track of peoples' names. We can 24 | store the names in [a list](../basics/lists-and-tuples.md), and adding a 25 | new name is easy as appending to that list. Lists remember their order 26 | and it's possible to add the same thing multiple times. 27 | 28 | ```python 29 | >>> names = ['wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori'] 30 | >>> names.append('Akuli') 31 | >>> names.append('Akuli') 32 | >>> names 33 | ['wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori', 'Akuli', 'Akuli'] 34 | >>> 35 | ``` 36 | 37 | This is usually what we need, but sometimes it's not. Sometimes we just 38 | want to store a bunch of things. We don't need to have the same thing 39 | twice and we don't care about the order. 40 | 41 | This is when sets come in. They are like lists without order or 42 | duplicates, or keys of [dictionaries](../basics/dicts.md) without the 43 | values. We can create a set just like a dictionary, but without `:`. 44 | 45 | ```python 46 | >>> names = {'wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori'} 47 | >>> names 48 | {'RubyPinch', 'theelous3', 'go|dfish', 'wub_wub', 'Nitori'} 49 | >>> type(names) 50 | 51 | >>> 'wub_wub' in names 52 | True 53 | >>> 54 | ``` 55 | 56 | We can also convert anything [iterable](../basics/loops.md#summary) to a 57 | set [by calling the 58 | class](../basics/classes.md#what-are-classes). 59 | 60 | ```python 61 | >>> set('hello') 62 | {'o', 'e', 'h', 'l'} 63 | >>> type(set('hello')) 64 | 65 | >>> 66 | ``` 67 | 68 | When we did `set('hello')` we lost one `l` and the set ended up in a 69 | different order because sets don't contain duplicates or keep track of 70 | their order. 71 | 72 | Note that `{}` is a dictionary because dictionaries are used more often 73 | than sets, so we need `set()` if we want to create an empty set. 74 | 75 | ```python 76 | >>> type({'a', 'b'}) 77 | 78 | >>> type({'a'}) 79 | 80 | >>> type({}) 81 | 82 | >>> type(set()) # set() is an empty set 83 | 84 | >>> 85 | ``` 86 | 87 | Sets have a `remove` method just like lists have, but they have an `add` 88 | method instead of `append`. 89 | 90 | ```python 91 | >>> names = {'theelous3', 'wub_wub'} 92 | >>> names.add('Akuli') 93 | >>> names 94 | {'wub_wub', 'Akuli', 'theelous3'} 95 | >>> names.remove('theelous3') 96 | >>> names 97 | {'wub_wub', 'Akuli'} 98 | >>> 99 | ``` 100 | 101 | That's the boring part. Now let's have a look at some really handy 102 | things we can do with sets: 103 | 104 | ```python 105 | >>> a = {'RubyPinch', 'theelous3', 'go|dfish'} 106 | >>> b = {'theelous3', 'Nitori'} 107 | >>> a & b # names in a and b 108 | {'theelous3'} 109 | >>> a | b # names in a, b or both 110 | {'Nitori', 'theelous3', 'go|dfish', 'RubyPinch'} 111 | >>> a ^ b # names in a or b, but not both 112 | {'RubyPinch', 'Nitori', 'go|dfish'} 113 | >>> a - b # names in a but not in b 114 | {'go|dfish', 'RubyPinch'} 115 | >>> 116 | ``` 117 | 118 | ## Named tuples 119 | 120 | It can be tempting to make a class that just contains a bunch of data 121 | and that's it. 122 | 123 | ```python 124 | class Website: 125 | 126 | def __init__(self, url, founding_year, free_to_use): 127 | self.url = url 128 | self.founding_year = founding_year 129 | self.free_to_use = free_to_use 130 | 131 | 132 | github = Website('https://github.com/', 2008, True) 133 | ``` 134 | 135 | You should avoid making classes like this. This class has only one 136 | method, so it doesn't really need to be a class. We could just use a 137 | tuple instead: 138 | 139 | ```python 140 | github = ('https://github.com/', 2008, True) 141 | ``` 142 | 143 | The problem with this is that if someone reading our code sees something 144 | like `website[1] > 2010` it doesn't make much sense, like 145 | `website.founding_year > 2010` would. 146 | 147 | In cases like this, `collections.namedtuple` is handy: 148 | 149 | ```python 150 | >>> Website = collections.namedtuple('Website', 'url founding_year free_to_use') 151 | >>> github = Website('https://github.com/', 2008, True) 152 | >>> github[1] 153 | 2008 154 | >>> for thing in github: 155 | ... print(thing) 156 | ... 157 | https://github.com/ 158 | 2008 159 | True 160 | >>> github.founding_year 161 | 2008 162 | >>> github 163 | Website(url='https://github.com/', founding_year=2008, free_to_use=True) 164 | >>> 165 | ``` 166 | 167 | As you can see, our `github` behaves like a tuple, but things like 168 | `github.founding_year` also work and `github` looks nice when we have a 169 | look at it on the `>>>` prompt. 170 | 171 | ## Deques 172 | 173 | To understand deques, we need to first learn about a list method I 174 | haven't talked about earlier. It's called `pop` and it works like this: 175 | 176 | ```python 177 | >>> names = ['wub_wub', 'theelous3', 'Nitori', 'RubyPinch', 'go|dfish'] 178 | >>> names 179 | ['wub_wub', 'theelous3', 'Nitori', 'RubyPinch', 'go|dfish'] 180 | >>> names.pop() 181 | 'go|dfish' 182 | >>> names 183 | ['wub_wub', 'theelous3', 'Nitori', 'RubyPinch'] 184 | >>> names.pop() 185 | 'RubyPinch' 186 | >>> names 187 | ['wub_wub', 'theelous3', 'Nitori'] 188 | >>> 189 | ``` 190 | 191 | The list shortens from the end by one when we pop from it, and we also 192 | get the removed item back. So we can add an item to the end of a list 193 | using `append`, and we can remove an item from the end using `pop`. 194 | 195 | It's also possible to do these things in the beginning of a list, but 196 | lists were not designed to be used that way and it would be slow if our 197 | list would be big. The `collections.deque` class makes appending and 198 | popping from both ends easy and fast. It works just like lists, but it 199 | also has `appendleft` and `popleft` methods. 200 | 201 | ```python 202 | >>> names = collections.deque(['theelous3', 'Nitori', 'RubyPinch']) 203 | >>> names 204 | deque(['theelous3', 'Nitori', 'RubyPinch']) 205 | >>> names.appendleft('wub_wub') 206 | >>> names.append('go|dfish') 207 | >>> names 208 | deque(['wub_wub', 'theelous3', 'Nitori', 'RubyPinch', 'go|dfish']) 209 | >>> names.popleft() 210 | 'wub_wub' 211 | >>> names.pop() 212 | 'go|dfish' 213 | >>> names 214 | deque(['theelous3', 'Nitori', 'RubyPinch']) 215 | >>> 216 | ``` 217 | 218 | The deque behaves a lot like lists do, and we can do `list(names)` if we 219 | need a list instead of a deque for some reason. 220 | 221 | Deques are often used as queues. It means that items are always added to 222 | one end and popped from the other end. 223 | 224 | ## Counting things 225 | 226 | Back in [the dictionary chapter](../basics/dicts.md#examples) we learned 227 | to count the number of words in a sentence like this: 228 | 229 | ```python 230 | sentence = input("Enter a sentence: ") 231 | counts = {} 232 | for word in sentence.split(): 233 | if word in counts: 234 | counts[word] += 1 235 | else: 236 | counts[word] = 1 237 | ``` 238 | 239 | This code works just fine, but there are easier ways to do this. For 240 | example, we could use the `get` method. It works so that 241 | `the_dict.get('hi', 'hello')` tries to give us `the_dict['hi']` but 242 | gives us `'hello'` instead if `'hi'` is not in the dictionary. 243 | 244 | ```python 245 | >>> the_dict = {'hi': 'this is working'} 246 | >>> the_dict.get('hi', 'lol its not there') 247 | 'this is working' 248 | >>> the_dict.get('hello', 'lol its not there') 249 | 'lol its not there' 250 | >>> 251 | ``` 252 | 253 | So we could write code like this instead: 254 | 255 | ```python 256 | sentence = input("Enter a sentence: ") 257 | counts = {} 258 | for word in sentence.split(): 259 | counts[word] = counts.get(word, 0) + 1 260 | ``` 261 | 262 | Counting things like this is actually so common that there's [a 263 | class](../basics/classes.md) just for that. It's called 264 | `collections.Counter` and it works like this: 265 | 266 | ```python 267 | >>> import collections 268 | >>> words = ['hello', 'there', 'this', 'test', 'is', 'a', 'hello', 'test'] 269 | >>> counts = collections.Counter(words) 270 | >>> counts 271 | Counter({'test': 2, 'hello': 2, 'is': 1, 'this': 1, 'there': 1, 'a': 1}) 272 | >>> 273 | ``` 274 | 275 | Now `counts` is a Counter object. It behaves a lot like a dictionary, 276 | and everything that works with a dictionary should also work with a 277 | counter. We can also convert the counter to a dictionary by doing 278 | `dict(the_counter)` if something doesn't work with a counter. 279 | 280 | ```python 281 | >>> for word, count in counts.items(): 282 | ... print(word, count) 283 | ... 284 | test 2 285 | is 1 286 | this 1 287 | there 1 288 | a 1 289 | hello 2 290 | >>> 291 | ``` 292 | 293 | ## Combining dictionaries 294 | 295 | We can add together strings, lists, tuples and sets easily. 296 | 297 | ```python 298 | >>> "hello" + "world" 299 | 'helloworld' 300 | >>> [1, 2, 3] + [4, 5] 301 | [1, 2, 3, 4, 5] 302 | >>> (1, 2, 3) + (4, 5) 303 | (1, 2, 3, 4, 5) 304 | >>> {1, 2, 3} | {4, 5} 305 | {1, 2, 3, 4, 5} 306 | >>> 307 | ``` 308 | 309 | But how about dictionaries? They can't be added together with `+`. 310 | 311 | ```python 312 | >>> {'a': 1, 'b': 2} + {'c': 3} 313 | Traceback (most recent call last): 314 | File "", line 1, in 315 | TypeError: unsupported operand type(s) for +: 'dict' and 'dict' 316 | >>> 317 | ``` 318 | 319 | Usually it's easiest to do this: 320 | 321 | ```python 322 | >>> dict1 = {'a': 1, 'b': 2} 323 | >>> dict2 = {'c': 3} 324 | >>> {**dict1, **dict2} 325 | {'a': 1, 'b': 2, 'c': 3} 326 | ``` 327 | 328 | Dictionaries also have an `update` method that adds everything from another 329 | dictionary into it, and you can use that too. This was the most common way to 330 | do it before Python supported `{**dict1, **dict2}`. 331 | 332 | ```python 333 | >>> merged = {} 334 | >>> merged.update({'a': 1, 'b': 2}) 335 | >>> merged.update({'c': 3}) 336 | >>> merged 337 | {'a': 1, 'b': 2, 'c': 3} 338 | >>> 339 | ``` 340 | 341 | ## Summary 342 | 343 | - Duck typing means requiring some behavior instead of some type. For 344 | example, instead of making a function that takes a list we could make 345 | a function that takes anything [iterable](../basics/loops.md#summary). 346 | - Sets and the collections module are handy. Use them. 347 | 348 | *** 349 | 350 | If you have trouble with this tutorial, please 351 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 352 | or [ask for help online](../getting-help.md). 353 | If you like this tutorial, please [give it a 354 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 355 | 356 | You may use this tutorial freely at your own risk. See 357 | [LICENSE](../LICENSE). 358 | 359 | [Previous](../basics/docstrings.md) | [Next](functions.md) | 360 | [List of contents](../README.md#advanced) 361 | -------------------------------------------------------------------------------- /basics/handy-stuff-strings.md: -------------------------------------------------------------------------------- 1 | # Handy stuff: Strings 2 | 3 | Python strings are just pieces of text. 4 | 5 | ```python 6 | >>> our_string = "Hello World!" 7 | >>> our_string 8 | 'Hello World!' 9 | >>> 10 | ``` 11 | 12 | So far we know how to add them together. 13 | 14 | ```python 15 | >>> "I said: " + our_string 16 | 'I said: Hello World!' 17 | >>> 18 | ``` 19 | 20 | We also know how to repeat them multiple times. 21 | 22 | ```python 23 | >>> our_string * 3 24 | 'Hello World!Hello World!Hello World!' 25 | >>> 26 | ``` 27 | 28 | Python strings are [immutable](https://docs.python.org/3/glossary.html#term-immutable). 29 | That's just a fancy way to say that 30 | they cannot be changed in-place, and we need to create a new string to 31 | change them. Even `some_string += another_string` creates a new string. 32 | Python will treat that as `some_string = some_string + another_string`, 33 | so it creates a new string but it puts it back to the same variable. 34 | 35 | `+` and `*` are nice, but what else can we do with strings? 36 | 37 | ## Slicing 38 | 39 | Slicing is really simple. It just means getting a part of the string. 40 | For example, to get all characters between the second place between the 41 | characters and the fifth place between the characters, we can do this: 42 | 43 | ```python 44 | >>> our_string[2:5] 45 | 'llo' 46 | >>> 47 | ``` 48 | 49 | So the syntax is like `some_string[start:end]`. 50 | 51 | This picture explains how the slicing works: 52 | 53 | ![Slicing with non-negative values](../images/slicing1.png) 54 | 55 | But what happens if we slice with negative values? 56 | 57 | ```python 58 | >>> our_string[-5:-2] 59 | 'orl' 60 | >>> 61 | ``` 62 | 63 | It turns out that slicing with negative values simply starts counting 64 | from the end of the string. 65 | 66 | ![Slicing with negative values](../images/slicing2.png) 67 | 68 | If we don't specify the beginning it defaults to 0, and if we don't 69 | specify the end it defaults to the length of the string. For example, we 70 | can get everything except the first or last character like this: 71 | 72 | ```python 73 | >>> our_string[1:] 74 | 'ello World!' 75 | >>> our_string[:-1] 76 | 'Hello World' 77 | >>> 78 | ``` 79 | 80 | Remember that strings can't be changed in-place. 81 | 82 | ```python 83 | >>> our_string[:5] = 'Howdy' 84 | Traceback (most recent call last): 85 | File "", line 1, in 86 | TypeError: 'str' object does not support item assignment 87 | >>> 88 | ``` 89 | 90 | There's also a step argument we can give to our slices, but I'm not 91 | going to talk about it now. 92 | 93 | ## Indexing 94 | 95 | So now we know how slicing works. But what happens if we forget the `:`? 96 | 97 | ```python 98 | >>> our_string[1] 99 | 'e' 100 | >>> 101 | ``` 102 | 103 | That's interesting. We got a string that is only one character long. But 104 | the first character of `Hello World!` should be `H`, not `e`, so why did 105 | we get an e? 106 | 107 | Programming starts at zero. Indexing strings also starts at zero. The 108 | first character is `our_string[0]`, the second character is 109 | `our_string[1]`, and so on. 110 | 111 | ```python 112 | >>> our_string[0] 113 | 'H' 114 | >>> our_string[1] 115 | 'e' 116 | >>> our_string[2] 117 | 'l' 118 | >>> our_string[3] 119 | 'l' 120 | >>> our_string[4] 121 | 'o' 122 | >>> 123 | ``` 124 | 125 | So string indexes work like this: 126 | 127 | ![Indexing with non-negative values](../images/indexing1.png) 128 | 129 | How about negative values? 130 | 131 | ```python 132 | >>> our_string[-1] 133 | '!' 134 | >>> 135 | ``` 136 | 137 | We got the last character. 138 | 139 | But why didn't that start at zero? `our_string[-1]` is the last 140 | character, but `our_string[1]` is not the first character! 141 | 142 | That's because 0 and -0 are equal, so indexing with -0 would do the same 143 | thing as indexing with 0. 144 | 145 | Indexing with negative values works like this: 146 | 147 | ![Indexing with negative values](../images/indexing2.png) 148 | 149 | ## String methods 150 | 151 | Python's strings have many useful methods. 152 | [The official documentation](https://docs.python.org/3/library/stdtypes.html#string-methods) 153 | covers them all, but I'm going to just show some of the most commonly 154 | used ones briefly. Python also comes with built-in documentation about 155 | the string methods and we can run `help(str)` to read it. We can also 156 | get help about one string method at a time, like `help(str.upper)`. 157 | 158 | Again, nothing can modify strings in-place. Most string methods 159 | return a new string, but things like `our_string = our_string.upper()` 160 | still work because the new string is assigned to the old variable. 161 | 162 | Also note that all of these methods are used like `our_string.stuff()`, 163 | not like `stuff(our_string)`. The idea with that is that our string 164 | knows how to do all these things, like `our_string.stuff()`, we don't 165 | need a separate function that does these things like `stuff(our_string)`. 166 | We'll learn more about methods [later](classes.md). 167 | 168 | Here's an example with some of the most commonly used string methods: 169 | 170 | ```python 171 | >>> our_string.upper() 172 | 'HELLO WORLD!' 173 | >>> our_string.lower() 174 | 'hello world!' 175 | >>> our_string.startswith('Hello') 176 | True 177 | >>> our_string.endswith('World!') 178 | True 179 | >>> our_string.endswith('world!') # Python is case-sensitive 180 | False 181 | >>> our_string.replace('World', 'there') 182 | 'Hello there!' 183 | >>> our_string.replace('o', '@', 1) # only replace one o 184 | 'Hell@ World!' 185 | >>> ' hello 123 '.lstrip() # left strip 186 | 'hello 123 ' 187 | >>> ' hello 123 '.rstrip() # right strip 188 | ' hello 123' 189 | >>> ' hello 123 '.strip() # strip from both sides 190 | 'hello 123' 191 | >>> ' hello abc'.rstrip('cb') # strip c's and b's from right 192 | ' hello a' 193 | >>> our_string.ljust(30, '-') 194 | 'Hello World!------------------' 195 | >>> our_string.rjust(30, '-') 196 | '------------------Hello World!' 197 | >>> our_string.center(30, '-') 198 | '---------Hello World!---------' 199 | >>> our_string.count('o') # it contains two o's 200 | 2 201 | >>> our_string.index('o') # the first o is our_string[4] 202 | 4 203 | >>> our_string.rindex('o') # the last o is our_string[7] 204 | 7 205 | >>> '-'.join(['hello', 'world', 'test']) 206 | 'hello-world-test' 207 | >>> 'hello-world-test'.split('-') 208 | ['hello', 'world', 'test'] 209 | >>> our_string.upper()[3:].startswith('LO WOR') # combining multiple things 210 | True 211 | >>> 212 | ``` 213 | 214 | The things in square brackets that the split method gave us and 215 | we gave to the join method were lists. We'll talk more about 216 | them [later](lists-and-tuples.md). 217 | 218 | ## String formatting 219 | 220 | To add a string in the middle of another string, we can do something 221 | like this: 222 | 223 | ```python 224 | >>> name = 'Akuli' 225 | >>> 'My name is ' + name + '.' 226 | 'My name is Akuli.' 227 | >>> 228 | ``` 229 | 230 | But that gets complicated if we have many things to add. 231 | 232 | ```python 233 | >>> channel = '##learnpython' 234 | >>> network = 'freenode' 235 | >>> "My name is " + name + " and I'm on the " + channel + " channel on " + network + "." 236 | "My name is Akuli and I'm on the ##learnpython channel on freenode." 237 | >>> 238 | ``` 239 | 240 | Instead it's recommended to use string formatting. It means putting 241 | other things in the middle of a string. 242 | 243 | Python has multiple ways to format strings. One is not necessarily 244 | better than others; they each have their own advantages and disadvantages. 245 | In this tutorial, we will focus on f-strings, which is the most common and usually the easiest way. 246 | 247 | `f` in f-strings stands for "format", f-strings are string literals that have an `f` at the beginning and curly braces containing expressions that will be replaced with their values at runtime. To create f-strings, you have to add an `f` or an `F` before the opening quotes of a string. 248 | 249 | ```python 250 | >>> f"My name is {name} and I'm on the {channel} channel on {network}." 251 | "My name is Akuli and I'm on the ##learnpython channel on freenode." 252 | >>> 253 | ``` 254 | 255 | ## Other things 256 | 257 | We can use `in` and `not in` to check if a string contains another 258 | string. 259 | 260 | ```python 261 | >>> our_string = "Hello World!" 262 | >>> "Hello" in our_string 263 | True 264 | >>> "Python" in our_string 265 | False 266 | >>> "Python" not in our_string 267 | True 268 | >>> 269 | ``` 270 | 271 | We can get the length of a string with the `len` function. The name 272 | `len` is short for "length". 273 | 274 | ```python 275 | >>> len(our_string) # 12 characters 276 | 12 277 | >>> len('') # no characters 278 | 0 279 | >>> len('\n') # python thinks of \n as one character 280 | 1 281 | >>> 282 | ``` 283 | 284 | We can convert strings, integers and floats with each other with 285 | `str`, `int` and `float`. They aren't actually functions, but they 286 | behave a lot like functions. We'll learn more about what they really 287 | are [later](classes.md). 288 | 289 | ```python 290 | >>> str(3.14) 291 | '3.14' 292 | >>> float('3.14') 293 | 3.14 294 | >>> str(123) 295 | '123' 296 | >>> int('123') 297 | 123 298 | >>> 299 | ``` 300 | 301 | Giving an invalid string to `int` or `float` produces an error 302 | message. 303 | 304 | ```python 305 | >>> int('lol') 306 | Traceback (most recent call last): 307 | File "", line 1, in 308 | ValueError: invalid literal for int() with base 10: 'lol' 309 | >>> float('hello') 310 | Traceback (most recent call last): 311 | File "", line 1, in 312 | ValueError: could not convert string to float: 'hello' 313 | >>> 314 | ``` 315 | 316 | ## Summary 317 | 318 | - Slicing returns a copy of a string with indexes from one index to 319 | another index. The indexes work like this: 320 | 321 | ![Slicing](../images/slicing3.png) 322 | 323 | - Indexing returns one character of a string. Remember that we don't 324 | need a `:` with indexing. The indexes work like this: 325 | 326 | ![Indexing](../images/indexing3.png) 327 | 328 | - Python has many string methods. Use 329 | [the documentation](https://docs.python.org/3/library/stdtypes.html#string-methods) 330 | or `help(str)` when you don't remember something about them. 331 | - String formatting means adding other things to the middle of a string. 332 | There are multiple ways to do this in Python. You should know how to 333 | use at least one of these ways. 334 | - The `in` keyword can be used for checking if a string contains another 335 | string. 336 | - `len(string)` returns string's length. 337 | - We can use `str`, `int` and `float` to convert values to different 338 | types. 339 | 340 | ## Exercises 341 | 342 | 1. Fix this program. 343 | 344 | ```python 345 | print("Hello!") 346 | word1 = input("Enter something: ") 347 | word2 = input("Enter another thing: ") 348 | word3 = input("Enter a third thing: ") 349 | word4 = input("And yet another thing: ") 350 | print("You entered " + word1 + ", " + word2 + ", " + word3 + " and " + word4 + ".") 351 | ``` 352 | 353 | 2. This program is supposed to say something loudly. Fix it. 354 | 355 | ```python 356 | message = input("What do you want me to say? ") 357 | message.upper 358 | print(message, "!!!") 359 | print(message, "!!!") 360 | print(message, "!!!") 361 | ``` 362 | 3. Make a program to ask a string from the user and check if it is a palindrome.
363 | (Hint: A string is a palindrome if it is the same when reversed. Google how to reverse a string.) 364 | 365 | The answers are [here](answers.md#handy-stuff-strings). 366 | 367 | *** 368 | 369 | If you have trouble with this tutorial, please 370 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 371 | or [ask for help online](../getting-help.md). 372 | If you like this tutorial, please [give it a 373 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 374 | 375 | You may use this tutorial freely at your own risk. See 376 | [LICENSE](../LICENSE). 377 | 378 | [Previous](if.md) | [Next](lists-and-tuples.md) | 379 | [List of contents](../README.md#basics) 380 | -------------------------------------------------------------------------------- /advanced/iters.md: -------------------------------------------------------------------------------- 1 | # Iterables, iterators and generators 2 | 3 | So far we have used for loops with many different kinds of things. 4 | 5 | ```python 6 | >>> for name in ['theelous3', 'RubyPinch', 'go|dfish']: 7 | ... print(name) 8 | ... 9 | theelous3 10 | RubyPinch 11 | go|dfish 12 | >>> for letter in 'abc': 13 | ... print(letter) 14 | ... 15 | a 16 | b 17 | c 18 | >>> 19 | ``` 20 | 21 | For looping over something is one way to **iterate** over it. Some other 22 | things also iterate, for example, `' '.join(['a', 'b', 'c'])` iterates 23 | over the list `['a', 'b', 'c']`. If we can iterate over something, then 24 | that something is **iterable**. For example, strings and lists are 25 | iterable, but integers and floats are not. 26 | 27 | ```python 28 | >>> for thing in 123: 29 | ... print(thing) 30 | ... 31 | Traceback (most recent call last): 32 | File "", line 1, in 33 | TypeError: 'int' object is not iterable 34 | >>> 35 | ``` 36 | 37 | ## Iterators 38 | 39 | Lists and strings don't change when we iterate over them. 40 | 41 | ```python 42 | >>> word = 'hi' 43 | >>> for character in word: 44 | ... print(character) 45 | ... 46 | h 47 | i 48 | >>> word 49 | 'hi' 50 | >>> 51 | ``` 52 | 53 | We can also iterate over [files](../basics/files.md), but they remember 54 | their position and we get the content once only if we iterate over them 55 | twice. 56 | 57 | ```python 58 | >>> with open('test.txt', 'w') as f: 59 | ... print("one", file=f) 60 | ... print("two", file=f) 61 | ... 62 | >>> a = [] 63 | >>> b = [] 64 | >>> with open('test.txt', 'r') as f: 65 | ... for line in f: 66 | ... a.append(line) 67 | ... for line in f: 68 | ... b.append(line) 69 | ... 70 | >>> a 71 | ['one\n', 'two\n'] 72 | >>> b 73 | [] 74 | >>> 75 | ``` 76 | 77 | We have also used [enumerate](../basics/zip-and-enumerate.md) 78 | before, and it actually remembers its position also: 79 | 80 | ```python 81 | >>> e = enumerate('hello') 82 | >>> for pair in e: 83 | ... print(pair) 84 | ... 85 | (0, 'h') 86 | (1, 'e') 87 | (2, 'l') 88 | (3, 'l') 89 | (4, 'o') 90 | >>> for pair in e: 91 | ... print(pair) 92 | ... 93 | >>> 94 | ``` 95 | 96 | **Iterators are iterables that remember their position.** For example, 97 | `open('test.txt', 'r')` and `enumerate('hello')` return iterators. 98 | Iterators can only be used once, so we need to create a new iterator if 99 | we want to do another for loop. 100 | 101 | All iterators are iterables, but not all iterables are iterators. Like 102 | this: 103 | 104 | ![Iterables and iterators.](../images/iters.png) 105 | 106 | ## Iterating manually 107 | 108 | Iterators have a magic method called `__next__` that gets next value and 109 | moves the iterator forward. 110 | 111 | ```python 112 | >>> e = enumerate('abc') 113 | >>> e.__next__() 114 | (0, 'a') 115 | >>> e.__next__() 116 | (1, 'b') 117 | >>> e.__next__() 118 | (2, 'c') 119 | >>> 120 | ``` 121 | 122 | There's also a built-in `next()` function that does the same thing: 123 | 124 | ```python 125 | >>> e = enumerate('abc') 126 | >>> next(e) 127 | (0, 'a') 128 | >>> next(e) 129 | (1, 'b') 130 | >>> next(e) 131 | (2, 'c') 132 | >>> 133 | ``` 134 | 135 | Here `e` remembers its position, and every time we call `next(e)` it 136 | gives us the next element and moves forward. When it has no more values 137 | to give us, calling `next(e)` raises a StopIteration: 138 | 139 | ```python 140 | >>> next(e) 141 | Traceback (most recent call last): 142 | File "", line 1, in 143 | StopIteration 144 | >>> 145 | ``` 146 | 147 | There is usually not a good way to check if the iterator is at the end, 148 | and it's best to just try to get a value from it and 149 | [catch](../basics/exceptions.md#catching-exceptions) StopIteration. 150 | 151 | That's actually what for loops do. For example, 152 | this code... 153 | 154 | ```python 155 | for pair in enumerate('hello'): 156 | print(pair) 157 | ``` 158 | 159 | ...does roughly the same thing as this code: 160 | 161 | ```python 162 | e = enumerate('hello') 163 | while True: 164 | try: 165 | pair = next(e) 166 | except StopIteration: 167 | # it's at the end, time to stop 168 | break 169 | # we got a pair 170 | print(pair) 171 | ``` 172 | 173 | The for loop version is much simpler to write and I wrote the while loop 174 | version just to show how the for loop works. 175 | 176 | ## Converting to iterators 177 | 178 | Now we know what iterating over an iterator does. But how about 179 | iterating over a list or a string? They are not iterators, so we can't 180 | call `next()` on them: 181 | 182 | ```python 183 | >>> next('abc') 184 | Traceback (most recent call last): 185 | File "", line 1, in 186 | TypeError: 'str' object is not an iterator 187 | >>> 188 | ``` 189 | 190 | There's a built-in function called `iter()` that converts anything 191 | iterable to an iterator. 192 | 193 | ```python 194 | >>> i = iter('abc') 195 | >>> i 196 | 197 | >>> next(i) 198 | 'a' 199 | >>> next(i) 200 | 'b' 201 | >>> next(i) 202 | 'c' 203 | >>> next(i) 204 | Traceback (most recent call last): 205 | File "", line 1, in 206 | StopIteration 207 | >>> 208 | ``` 209 | 210 | Calling `iter()` on anything non-iterable gives us an error. 211 | 212 | ```python 213 | >>> iter(123) 214 | Traceback (most recent call last): 215 | File "", line 1, in 216 | TypeError: 'int' object is not iterable 217 | >>> 218 | ``` 219 | 220 | If we try to convert an iterator to an iterator using `iter()` we just 221 | get back the same iterator. 222 | 223 | ```python 224 | >>> e = enumerate('abc') 225 | >>> iter(e) is e 226 | True 227 | >>> 228 | ``` 229 | 230 | So code like this... 231 | 232 | ```python 233 | for thing in stuff: 234 | print(thing) 235 | ``` 236 | 237 | ...works roughly like this: 238 | 239 | ```python 240 | iterator = iter(stuff) 241 | while True: 242 | try: 243 | thing = next(iterator) 244 | except StopIteration: 245 | break 246 | print(thing) 247 | ``` 248 | 249 | ## Checking if object is iterable or not 250 | 251 | There is an easy way of checking if an object in python is iterable or not. The following code will do the needful. 252 | ```python 253 | >>> def check(A): 254 | ... try: 255 | ... st = iter(A) 256 | ... print('yes') 257 | ... except TypeError: 258 | ... print('no') 259 | ... 260 | >>> check(25) 261 | no 262 | >>> check([25,35]) 263 | yes 264 | >>> 265 | ``` 266 | Here you can observe that the 25 is an integer, so it is not iterable, but [25,35] is a list which is iterable so it outputs no and yes respectively. 267 | 268 | ## Generators 269 | 270 | It's possible to create a custom iterator with a class that defines an 271 | `__iter__` method that returns self and a `__next__` method that gets 272 | the next value. I'm not going to talk about it now because there's a 273 | much simpler way to implement iterators. Let's make a function that 274 | creates an iterator that behaves like `iter([1, 2, 3])` using the 275 | `yield` keyword: 276 | 277 | ```python 278 | >>> def thingy(): 279 | ... yield 1 280 | ... yield 2 281 | ... yield 3 282 | ... 283 | >>> 284 | ``` 285 | 286 | We can only `yield` inside a function, yielding elsewhere raises an 287 | error. 288 | 289 | ```python 290 | >>> yield 'hi' 291 | File "", line 1 292 | SyntaxError: 'yield' outside function 293 | >>> 294 | ``` 295 | 296 | Let's try out our thingy function and see how it works. 297 | 298 | ```python 299 | >>> thingy() 300 | 301 | >>> 302 | ``` 303 | 304 | What the heck? We don't return anything from the function, but it still 305 | doesn't return None! 306 | 307 | Putting a `yield` anywhere in a function makes it return **generators**. 308 | **Generators are iterators** with some more features that we don't need 309 | to care about. 310 | 311 | ![Generators.](../images/generators.png) 312 | 313 | The generators that thingy gives us work just like other iterators: 314 | 315 | ```python 316 | >>> t = thingy() 317 | >>> t 318 | 319 | >>> next(t) 320 | 1 321 | >>> next(t) 322 | 2 323 | >>> next(t) 324 | 3 325 | >>> next(t) 326 | Traceback (most recent call last): 327 | File "", line 1, in 328 | StopIteration 329 | >>> for number in thingy(): 330 | ... print(number) 331 | ... 332 | 1 333 | 2 334 | 3 335 | >>> 336 | ``` 337 | 338 | This whole thing may feel kind of insane. If we add some parts between 339 | the yields, when do they run? How does Python know when to run what? 340 | 341 | Let's find out. 342 | 343 | ```python 344 | >>> def printygen(): 345 | ... print("starting") 346 | ... yield 1 347 | ... print("between 1 and 2") 348 | ... yield 2 349 | ... print("between 2 and 3") 350 | ... yield 3 351 | ... print("end") 352 | ... 353 | >>> p = printygen() 354 | >>> 355 | ``` 356 | 357 | That's weird! We called it, but it didn't print "starting"! 358 | 359 | Let's see what happens if we call `next()` on it. 360 | 361 | ```python 362 | >>> got = next(p) 363 | starting 364 | >>> got 365 | 1 366 | >>> 367 | ``` 368 | 369 | Now it started, but it's frozen! It's just stuck on that `yield 1`. 370 | 371 | An easy way to think about this is to compare it to our computers. 372 | When we suspend a computer it goes into some kind of stand-by mode, 373 | and we can later continue using the computer all of our programs are 374 | still there just like they were when we left. 375 | 376 | A similar thing happens here. Our function is running, but it's just 377 | stuck at the yield and waiting for us to call `next()` on it again. 378 | 379 | ```python 380 | >>> next(p) 381 | between 1 and 2 382 | 2 383 | >>> next(p) 384 | between 2 and 3 385 | 3 386 | >>> next(p) 387 | end 388 | Traceback (most recent call last): 389 | File "", line 1, in 390 | StopIteration 391 | >>> 392 | ``` 393 | 394 | Here's a drawing of what's going on: 395 | 396 | ![A picture of printygen.](../images/freeze-melt.png) 397 | 398 | The good news is that **usually we don't need to worry about when 399 | exactly the parts between the yields run**. Actually we don't even need 400 | to use `iter()` and `next()` most of the time, but I think it's nice to 401 | know how for loops work. 402 | 403 | `yield` is useful when we want the function to output so many things 404 | that making a list of them would be too slow or the list wouldn't fit in 405 | the computer's memory. So instead of this... 406 | 407 | ```python 408 | def get_things(): 409 | result = [] 410 | # code that appends things to result 411 | return result 412 | ``` 413 | 414 | ...we can do this: 415 | 416 | ```python 417 | def get_things(): 418 | # code that yields stuff 419 | ``` 420 | 421 | Both of these functions can be used like this: 422 | 423 | ```python 424 | for thing in get_things(): 425 | # do something with thing 426 | ``` 427 | 428 | It's actually possible to create an iterator that yields an infinite 429 | number of things: 430 | 431 | ```python 432 | >>> def count(): 433 | ... current = 1 434 | ... while True: 435 | ... yield current 436 | ... current += 1 437 | ... 438 | >>> c = count() 439 | >>> next(c) 440 | 1 441 | >>> next(c) 442 | 2 443 | >>> next(c) 444 | 3 445 | >>> next(c) 446 | 4 447 | >>> 448 | ``` 449 | 450 | [The itertools module](https://docs.python.org/3/library/itertools.html) 451 | contains many useful things like this. For example, `itertools.count(1)` 452 | does the same thing as our `count()`. 453 | 454 | ## Summary 455 | 456 | - An iterable is something that we can for loop over. 457 | - An iterator is an iterable that remembers its position. 458 | - For loops create an iterator of the iterable and call its `__next__` 459 | method until it raises a StopIteration. 460 | - Functions that contain yields return generators. Calling `next()` on a 461 | generator runs it to the next yield and gives us the value it yielded. 462 | - [The itertools module](https://docs.python.org/3/library/itertools.html) 463 | contains many useful iterator-related things. 464 | *** 465 | 466 | If you have trouble with this tutorial, please 467 | [tell me about it](../contact-me.md) and I'll make this tutorial better, 468 | or [ask for help online](../getting-help.md). 469 | If you like this tutorial, please [give it a 470 | star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). 471 | 472 | You may use this tutorial freely at your own risk. See 473 | [LICENSE](../LICENSE). 474 | 475 | [Previous](magicmethods.md) | [Next](../README.md) | 476 | [List of contents](../README.md#advanced) 477 | --------------------------------------------------------------------------------