diff --git a/LICENSE b/LICENSE index 3d067ad..93baa59 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ The instructions and text in this tutorial (the "software") are licensed under the zlib License. - (C) 2016-2017 Akuli + (C) 2016-2021 Akuli This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/README.md b/README.md index feef6cc..f8e350d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Python programming tutorial +# Python programming tutorial for beginners This is a concise Python 3 programming tutorial for people who think that reading is boring. I try to show everything with simple code @@ -12,14 +12,8 @@ or very little programming experience. If you have programmed a lot in the past using some other language you may want to read [the official tutorial](https://docs.python.org/3/tutorial/) instead. -You can use Python 3.3 or any newer Python with this tutorial. **Don't -use Python 2.** If you write a Python 2 program now someone will need to -convert it to Python 3 later, so it's best to just write Python 3 to -begin with. Python 3 code will work just fine in Python 4, so you don't -need to worry about that. Python 2 also has horrible -[Unicode](http://www.unicode.org/standard/WhatIsUnicode.html) problems, -so it's difficult to write Python 2 code that works correctly with -non-English characters (like π and ♫). +You can use Python 3.6 or any newer Python with this tutorial. **Don't +use Python 2 because it's no longer supported.** ## List of contents @@ -41,7 +35,7 @@ to learn more about whatever you want after studying it. 9. [Handy stuff with strings](basics/handy-stuff-strings.md) 10. [Lists and tuples](basics/lists-and-tuples.md) 11. [Loops](basics/loops.md) -12. [Trey Hunner: zip and enumerate](basics/trey-hunner-zip-and-enumerate.md) +12. [zip and enumerate](basics/zip-and-enumerate.md) 13. [Dictionaries](basics/dicts.md) 14. [Defining functions](basics/defining-functions.md) 15. [Writing a larger program](basics/larger-program.md) @@ -59,7 +53,7 @@ section. Most of the techniques explained here are great when you're working on a large project, and your code would be really repetitive without these things. -You can experient with these things freely, but please **don't use these +You can experiment with these things freely, but please **don't use these techniques just because you know how to use them.** Prefer the simple techniques from the Basics part instead when possible. Simple is better than complex. @@ -73,7 +67,7 @@ than complex. - **Important:** [getting help](getting-help.md) - [Contact me](contact-me.md) -- Answers for excercises in [basics](basics/answers.md) and +- Answers for exercises in [basics](basics/answers.md) and [advanced](advanced/answers.md) sections - [The TODO list](TODO.md) @@ -110,17 +104,15 @@ pull with git and run `make-html.py` again. ## Authors -I'm Akuli and I have written most of this tutorial, but these people -have helped me with it: -- [SpiritualForest](https://github.com/SpiritualForest): Lots of typing - error fixes. -- [theelous3](https://github.com/theelous3): Small improvements and fixes. +I'm Akuli and I have written most of this tutorial, but other people have helped me with it. +See [github's contributors page](https://github.com/Akuli/python-tutorial/graphs/contributors) for details. *** -If you have trouble with this tutorial please [tell me about -it](./contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](./contact-me.md) and I'll make this tutorial better, +or [ask for help online](./getting-help.md). +If you like this tutorial, please [give it a star](./README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/TODO.md b/TODO.md index 53b2bc3..ff1ecde 100644 --- a/TODO.md +++ b/TODO.md @@ -40,9 +40,10 @@ This tutorial is not complete. It still needs: *** -If you have trouble with this tutorial please [tell me about -it](./contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](./contact-me.md) and I'll make this tutorial better, +or [ask for help online](./getting-help.md). +If you like this tutorial, please [give it a star](./README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/advanced/README.md b/advanced/README.md index cfa964c..bbb46e5 100644 --- a/advanced/README.md +++ b/advanced/README.md @@ -8,7 +8,7 @@ section. Most of the techniques explained here are great when you're working on a large project, and your code would be really repetitive without these things. -You can experient with these things freely, but please **don't use these +You can experiment with these things freely, but please **don't use these techniques just because you know how to use them.** Prefer the simple techniques from the Basics part instead when possible. Simple is better than complex. @@ -20,9 +20,10 @@ than complex. *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/advanced/answers.md b/advanced/answers.md index d6a4371..ca52c7f 100644 --- a/advanced/answers.md +++ b/advanced/answers.md @@ -1,9 +1,10 @@ *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/advanced/datatypes.md b/advanced/datatypes.md index 7dd7574..456d777 100644 --- a/advanced/datatypes.md +++ b/advanced/datatypes.md @@ -1,10 +1,10 @@ # Handy data types in the standard library -[](this doesn't explain how dict.setdefault and collections.defaultdict - work because they're not as simple as the things that are here and i - don't actually use them that much) +[comment]: # (this doesn't explain how dict.setdefault and collections.defaultdict) +[comment]: # (work because they're not as simple as the things that are here and i) +[comment]: # (don't actually use them that much) -Now we know how to ues lists, tuples and dictionaries. They are commonly +Now we know how to use lists, tuples and dictionaries. They are commonly used data types in Python, and there's nothing wrong with them. In this chapter we'll learn more data types that make some things easier. You can always do everything with lists and dictionaries, but these data @@ -65,7 +65,7 @@ class](../basics/classes.md#what-are-classes). >>> ``` -When we did `set('hello')` we lost one `h` and the set ended up in a +When we did `set('hello')` we lost one `l` and the set ended up in a different order because sets don't contain duplicates or keep track of their order. @@ -316,68 +316,25 @@ TypeError: unsupported operand type(s) for +: 'dict' and 'dict' >>> ``` -Dictionaries have an `update` method that adds everything from another -dictionary into it. So we can merge dictionaries like this: +Usually it's easiest to do this: ```python ->>> merged = {} ->>> merged.update({'a': 1, 'b': 2}) ->>> merged.update({'c': 3}) ->>> merged -{'c': 3, 'b': 2, 'a': 1} ->>> -``` - -Or we can [write a function](../basics/defining-functions.md) like this: - -```python ->>> def merge_dicts(dictlist): -... result = {} -... for dictionary in dictlist: -... result.update(dictionary) -... return result -... ->>> merge_dicts([{'a': 1, 'b': 2}, {'c': 3}]) -{'c': 3, 'b': 2, 'a': 1} ->>> +>>> dict1 = {'a': 1, 'b': 2} +>>> dict2 = {'c': 3} +>>> {**dict1, **dict2} +{'a': 1, 'b': 2, 'c': 3} ``` -Kind of like counting things, merging dictionaries is also a commonly -needed thing and there's a class just for it in the `collections` -module. It's called ChainMap: +Dictionaries also have an `update` method that adds everything from another +dictionary into it, and you can use that too. This was the most common way to +do it before Python supported `{**dict1, **dict2}`. ```python ->>> import collections ->>> merged = collections.ChainMap({'a': 1, 'b': 2}, {'c': 3}) +>>> merged = {} +>>> merged.update({'a': 1, 'b': 2}) +>>> merged.update({'c': 3}) >>> merged -ChainMap({'b': 2, 'a': 1}, {'c': 3}) ->>> -``` - -Our `merged` is kind of like the Counter object we created earlier. It's -not a dictionary, but it behaves like a dictionary. - -```python ->>> for key, value in merged.items(): -... print(key, value) -... -c 3 -b 2 -a 1 ->>> dict(merged) -{'c': 3, 'b': 2, 'a': 1} ->>> -``` - -Starting with Python 3.5 it's possible to merge dictionaries like this. -**Don't do this unless you are sure that no-one will need to run your -code on Python versions older than 3.5.** - -```python ->>> first = {'a': 1, 'b': 2} ->>> second = {'c': 3, 'd': 4} ->>> {**first, **second} -{'d': 4, 'c': 3, 'a': 1, 'b': 2} +{'a': 1, 'b': 2, 'c': 3} >>> ``` @@ -390,9 +347,10 @@ code on Python versions older than 3.5.** *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/advanced/functions.md b/advanced/functions.md index 6accb1e..8f54e60 100644 --- a/advanced/functions.md +++ b/advanced/functions.md @@ -50,7 +50,7 @@ For example, instead of this... ```python def get_new_info(username): - print("Changing user information of %s." % username) + print(f"Changing user information of {username}.") username = input("New username: ") password = input("New password: ") fullname = input("Full name: ") @@ -66,7 +66,7 @@ class User: # them here def change_info(self): - print("Changing user information of %s." % self.username) + print(f"Changing user information of {self.username}.") self.username = input("New username: ") self.password = input("New password: ") self.fullname = input("Full name: ") @@ -290,9 +290,10 @@ does, so using keyword-only arguments makes sense. *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/advanced/iters.md b/advanced/iters.md index 58cebbc..450e763 100644 --- a/advanced/iters.md +++ b/advanced/iters.md @@ -74,7 +74,7 @@ twice. >>> ``` -We have also used [enumerate](../basics/trey-hunner-zip-and-enumerate.md) +We have also used [enumerate](../basics/zip-and-enumerate.md) before, and it actually remembers its position also: ```python @@ -246,6 +246,25 @@ while True: print(thing) ``` +## Checking if object is iterable or not + +There is an easy way of checking if an object in python is iterable or not. The following code will do the needful. +```python +>>> def check(A): +... try: +... st = iter(A) +... print('yes') +... except TypeError: +... print('no') +... +>>> check(25) +no +>>> check([25,35]) +yes +>>> +``` +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. + ## Generators It's possible to create a custom iterator with a class that defines an @@ -442,12 +461,12 @@ does the same thing as our `count()`. generator runs it to the next yield and gives us the value it yielded. - [The itertools module](https://docs.python.org/3/library/itertools.html) contains many useful iterator-related things. - *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/advanced/magicmethods.md b/advanced/magicmethods.md index c7f6e28..c333bbe 100644 --- a/advanced/magicmethods.md +++ b/advanced/magicmethods.md @@ -112,13 +112,10 @@ the message is 'hello' Combining `repr()` with [string formatting](../basics/handy-stuff-strings.md#string-formatting) is also -easy. `%` formatting has a `%r` formatter, and `.format()` formatting -has a `!r` flag. +easy. ```python ->>> print("the message is %r" % (message,)) -the message is 'hello' ->>> print("the message is {!r}".format(message)) +>>> print(f"the message is {repr(message)}") the message is 'hello' >>> ``` @@ -155,8 +152,7 @@ follow one of these styles: ... self.name = name ... self.founding_year = founding_year ... def __repr__(self): - ... return 'Website(name=%r, founding_year=%r)' % ( - ... self.name, self.founding_year) + ... return f'Website(name={repr(self.name)}, founding_year={repr(self.founding_year)})' ... >>> github = Website('GitHub', 2008) >>> github @@ -174,8 +170,7 @@ follow one of these styles: ... self.name = name ... self.founding_year = founding_year ... def __repr__(self): - ... return '' % ( - ... self.name, self.founding_year) + ... return f'' ... >>> github = Website('GitHub', 2008) >>> github @@ -235,9 +230,10 @@ are not meant to be imported. *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/README.md b/basics/README.md index 24f8547..23d1059 100644 --- a/basics/README.md +++ b/basics/README.md @@ -17,7 +17,7 @@ to learn more about whatever you want after studying it. 9. [Handy stuff with strings](handy-stuff-strings.md) 10. [Lists and tuples](lists-and-tuples.md) 11. [Loops](loops.md) -12. [Trey Hunner: zip and enumerate](trey-hunner-zip-and-enumerate.md) +12. [zip and enumerate](zip-and-enumerate.md) 13. [Dictionaries](dicts.md) 14. [Defining functions](defining-functions.md) 15. [Writing a larger program](larger-program.md) @@ -30,9 +30,10 @@ to learn more about whatever you want after studying it. *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/answers.md b/basics/answers.md index e05d77d..766ec70 100644 --- a/basics/answers.md +++ b/basics/answers.md @@ -25,14 +25,16 @@ isn't exactly like mine but it works just fine it's ok, and you can `print('You entered:', something)`. 2. The broken code has mostly the same issues as exercise 1. Here are - the problems that excercise 1 doesn't have: + the problems that exercise 1 doesn't have: + - The if-elif-else has a blank line at a confusing place. Delete it. + - After deleting the code, it looks quite dense. Add a new blank + line before the `if`. - The elif line is missing a `:` at the end. - On the last line the comma is on the wrong side. `"bla bla,"` is - a string that **contains** a comma, but `"bla bla",` is a - string and a **separate** comma. In this exercise, the last - line should be - `print("I don't know what", something, "means.")` + a string that **contains** a comma, but `"bla bla",` is a + string and a **separate** comma. In this exercise, the last + line should be `print("I don't know what", something, "means.")` 3. We can simply ask the word with input and print `word * 1000`. @@ -64,7 +66,7 @@ isn't exactly like mine but it works just fine it's ok, and you can ```python no_space = input("Enter a word: ") yes_space = no_space + " " - print(yes_space * 999 + no_space) + print(yes_space*999 + no_space) ``` 5. Like this: @@ -77,12 +79,12 @@ isn't exactly like mine but it works just fine it's ok, and you can ``` 6. We can compare the word against an empty string (`""` or `''`) to - check if it's empty. In this example, the password is "s3cr3t". + check if it's empty. In this example, the password is "seKr3t". ```python word = input("Enter your password: ") - if word == "s3cr3t": + if word == "seKr3t": print("Welcome!") elif word == "": print("You didn't enter anything.") @@ -90,8 +92,7 @@ isn't exactly like mine but it works just fine it's ok, and you can print("Access denied.") ``` - This is not a good way to ask a password from the user because the - password isn't hidden in any way, but this is just an example. + Again, this is not a good way to ask a real password from the user. ## Handy stuff: Strings @@ -99,16 +100,7 @@ isn't exactly like mine but it works just fine it's ok, and you can just fine if we run it, but there's a problem. The last line is really long and it's hard to see what it does. - The solution is string formatting. At the time of writing this, I - recommend replacing the last line with one of these: - - ```python - print("You entered %s, %s, %s and %s." % (word1, word2, word3, word4)) - print("You entered {}, {}, {} and {}.".format(word1, word2, word3, word4)) - ``` - - In the future when most people will have Python 3.6 or newer, you - can also use this: + The solution is string formatting. I recommend replacing the last line with this: ```python print(f"You entered {word1}, {word2}, {word3} and {word4}.") @@ -155,7 +147,15 @@ isn't exactly like mine but it works just fine it's ok, and you can print(message, "!!!") print(message, "!!!") ``` - +3. In the code below, `palindrome_input[::-1]` is the string `palindrome_input` reversed. + For example, if `palindrome_input` is `"hello"`, then `palindrome_input[::-1]` is `"olleh"`. + ```python + palindrome_input = input("Enter a string: ") + if palindrome_input == palindrome_input[::-1]: + print("This string is a palindrome") + else: + print("This string is not a palindrome") + ``` ## Lists and tuples 1. Look carefully. The `namelist` is written in `()` instead of `[]`, @@ -217,7 +217,8 @@ isn't exactly like mine but it works just fine it's ok, and you can problems and solutions: - `namelist` is None. It should be `namelist.extend('theelous3')`, - not `namelist = namelist.extend('theelous3')`. + not `namelist = namelist.extend('theelous3')`. See [this + thing](using-functions.md#return-values). - Now the namelist is like `['wub_wub', ..., 't', 'h', 'e', 'e', ...]`. Python treated `'theelous3'` like a list so it added each of its characters to `namelist`. We can use `namelist.append('theelous3')` @@ -294,6 +295,36 @@ isn't exactly like mine but it works just fine it's ok, and you can print(converted_numbers) ``` +5. ``` python + row_count = int(input("Type the number of rows needed:")) + for column_count in range(1, row_count+1): + # Print numbers from 1 to column_count + for number in range(1, column_count+1): + print(number, end=" ") + print() # creates a new line for the next row + ``` + If the user enters 5, we want to do a row with 1 column, then 2 columns, and so on until 5 columns. + That would be `for column_count in range(1, 6)`, because the end of the range is excluded. + In general, we need to specify `row_count + 1` so that it actually ends at `row_count`. + The second loop is similar. + + Usually `print(number)` puts a newline character at the end of the line, so that the next print goes to the next line. + To get all numbers on the same line, we use a space instead of a newline character, + but we still need `print()` to add a newline character once we have printed the entire row. + + + +6. ```python + row_count=int(input("Type the number of rows needed:")) + + for line_number in range(1, row_count+1): + for number in range(line_number, row_count+1): + print(number, end=' ') + print() + ``` + Just like in the previous exercise, if the user enters 5, the first `for` loop gives the line numbers `1, 2, 3, 4, 5`.
+ For example, on line 2, we should print numbers from 2 to 5, as in `range(2, 6)`, or in general, `range(line_number, row_count+1)`. + ## Trey Hunner: zip and enumerate 1. Read some lines with `input` into a list and then enumerate it. @@ -433,9 +464,10 @@ isn't exactly like mine but it works just fine it's ok, and you can *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/classes.md b/basics/classes.md index aac9139..0b2a284 100644 --- a/basics/classes.md +++ b/basics/classes.md @@ -304,7 +304,7 @@ Free to use: True It's working. The `self` argument in `Website.info` was `github`. You could call it something else too such as `me`, `this` or `instance`, but use `self` instead. Other Python users have gotten used to it, and -the official style guide recommens it also. +the official style guide recommends it also. We still need to set `url`, `founding_year` and `free_to_use` manually. Maybe we could add a method to do that? @@ -416,9 +416,10 @@ print("You entered " + word + ".") *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/defining-functions.md b/basics/defining-functions.md index cee0d60..9b78b94 100644 --- a/basics/defining-functions.md +++ b/basics/defining-functions.md @@ -177,20 +177,16 @@ However, modifying a global variable in-place from a function is easy. >>> ``` -This doesn't work if the value is of an immutable type, like string or -integer because immutable values cannot be modified in-place. -Fortunately, Python will tell us if something's wrong. +This only works for changing in-place, we cannot assign a new value to +the variable. ```python ->>> thing = 1 ->>> def stuff(): -... thing += 1 +>>> def set_stuff_to_something_new(): +... stuff = ['more local stuff'] ... ->>> stuff() -Traceback (most recent call last): - File "", line 1, in - File "", line 2, in stuff -UnboundLocalError: local variable 'thing' referenced before assignment +>>> set_stuff_to_something_new() +>>> stuff +['global stuff', 'local stuff'] >>> ``` @@ -262,10 +258,6 @@ This function can be called in two ways: because `message = "hi"` and `some_function(message="hi")` do two completely different things. -Personally, I would use this function with a positional argument. It -only takes one argument, so I don't need to worry about which argument -is which. - Now it's time to solve our box printing problem: ```python @@ -461,7 +453,7 @@ howdy hi Typing `say_hi` just gives us the value of the `say_hi` variable, which is the function we defined. But `say_hi()` **calls** that function, so it runs and gives us a return value. The return value is None so the -`>>>` prompt [doesn't show it](#variables.md#none). +`>>>` prompt [doesn't show it](variables.md#none). But we know that the print function shows None, so what happens if we wrap the whole thing in `print()`? @@ -476,7 +468,7 @@ None ``` The `print(say_hi())` thing looks a bit weird at first, but it's easy to -understand. There's a print insnde `say_hi` and there's also the print +understand. There's a print inside `say_hi` and there's also the print we just wrote, so two things are printed. Python first ran `say_hi()`, and it returned None so Python did `print(None)`. Adding an extra `print()` around a function call is actually a common mistake, and I @@ -518,7 +510,7 @@ colors = ['red', 'yellow', 'blue', 'green', 'orange', 'pink', 'black', 'gray', 'white', 'brown'] choice = ask_until_correct("What's your favorite color?", colors, error_message="I don't know that color.") -print("Your favorite color is %s!" % choice) +print(f"Your favorite color is {choice}!") ``` ## Summary @@ -580,9 +572,10 @@ Answers for the first, second and third exercise are *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/dicts.md b/basics/dicts.md index 093b1fb..597d1eb 100644 --- a/basics/dicts.md +++ b/basics/dicts.md @@ -61,7 +61,7 @@ favorite_pets = { ``` Here `'horusr'` and `'caisa64'` are **keys** in the dictionary, and -`'cats'` and `'cats and docs'` are their **values**. Dictionaries are +`'cats'` and `'cats and dogs'` are their **values**. Dictionaries are often named by their values. This dictionary has favorite pets as its values so I named the variable `favorite_pets`. @@ -324,13 +324,14 @@ Running the program might look like this: *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See [LICENSE](../LICENSE). -[Previous](trey-hunner-zip-and-enumerate.md) | [Next](defining-functions.md) | +[Previous](zip-and-enumerate.md) | [Next](defining-functions.md) | [List of contents](../README.md#basics) diff --git a/basics/docstrings.md b/basics/docstrings.md index bbebfa3..c30cd7c 100644 --- a/basics/docstrings.md +++ b/basics/docstrings.md @@ -44,7 +44,7 @@ thing(stuff) ``` That sucked! We have no idea about what it does based on this. All we -know is that it takes a `thing` argument. +know is that it takes a `stuff` argument. This is when documentation strings or docstrings come in. All we need to do is to add a string to the beginning of our function and it will show @@ -198,11 +198,143 @@ this thing out of it. You might be wondering what `__weakref__` is. You don't need to care about it, and I think it would be better if `help()` would hide it. +## Popular Docstring Formats + +There are different styles for writing docstrings. If you are contributing to +another Python project, make sure to use the same style as rest of that project +is using. + +If you are starting a new project, then you can use whichever style you +want, but don't "reinvent the wheel"; use an existing style instead instead of +making up your own. Here are some examples of popular docstring styles to choose +from: + +### Sphinx Style + +[Sphinx](https://www.sphinx-doc.org/en/master/) is the Python documentation tool +that [the official Python documentation](https://docs.python.org/3/) uses. +By default, sphinx expects you to write docstrings like this: + +```python +class Vehicles: + """ + The Vehicles object contains lots of vehicles. + :param arg: The arg is used for ... + :type arg: str + :ivar arg: This is where we store arg + :vartype arg: str + """ + + def __init__(self, arg): + self.arg = arg + + def cars(self, distance, destination): + """We can't travel a certain distance in vehicles without fuels, so here's the fuels + + :param distance: The amount of distance traveled + :type amount: int + :param bool destinationReached: Should the fuels be refilled to cover required distance? + :raises: :class:`RuntimeError`: Out of fuel + + :returns: A Car mileage + :rtype: Cars + """ + ... +``` + +### Google Style + +Google Style is meant to be easier to read and use without a tool like sphinx. +Sphinx can be configured to use that with +[sphinx.ext.napoleon](https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html). + +```python +class Vehicles: + """ + The Vehicles object contains lots of vehicles. + + Args: + arg (str): The arg is used for... + + Attributes: + arg (str): This is where we store arg. + """ + + def __init__(self, arg): + self.arg = arg + + def cars(self, distance, destination): + """We can't travel distance in vehicles without fuels, so here is the fuels + + Args: + distance (int): The amount of distance traveled + destination (bool): Should the fuels refilled to cover the distance? + + Raises: + RuntimeError: Out of fuel + + Returns: + cars: A car mileage + """ + ... + +``` + +### Numpy Style + +[Numpy](https://numpy.org/) is a large and popular Python library, +and numpy developers have their own docstring style. + +```python +class Vehicles: + """ + The Vehicles object contains lots of vehicles. + + Parameters + ---------- + arg : str + The arg is used for ... + *args + The variable arguments are used for ... + **kwargs + The keyword arguments are used for ... + + Attributes + ---------- + arg : str + This is where we store arg. + """ + + def __init__(self, arg): + self.arg = arg + + def cars(self, distance, destination): + """We can't travel distance in vehicles without fuels, so here is the fuels + + Parameters + ---------- + distance : int + The amount of distance traveled + destination : bool + Should the fuels refilled to cover the distance? + + Raises + ------ + RuntimeError + Out of fuel + + Returns + ------- + cars + A car mileage + """ + pass +``` + ## When should we use docstrings? -Always use docstrings when writing code that other people will import. -The `help()` function is awesome, so it's important to make sure it's -actually helpful. +I recommend using docstrings when writing code that other people will import. +The `help()` function is awesome, so it's good to make sure it's actually helpful. If your code is not meant to be imported, docstrings are usually a good idea anyway. Other people reading your code will understand what it's @@ -214,13 +346,14 @@ doing without having to read through all of the code. - A `"""triple-quoted string"""` string in the beginning of a function, class or file is a docstring. It shows up in `help()`. - Docstrings are not comments. -- Usually it's a good idea to add docstrings everywhere +- Usually it's a good idea to add docstrings everywhere. *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/editor-setup.md b/basics/editor-setup.md index 4176cf4..be13ea5 100644 --- a/basics/editor-setup.md +++ b/basics/editor-setup.md @@ -1,7 +1,7 @@ # Setting up an editor for programming An editor is a program that lets us write longer programs than we can -write on the `>>>` prompt. Then we can save the programs to files and +write on the `>>>` prompt. With an editor we can save the programs to files and run them as many times as we want without writing them again. When programmers say "editor" they don't mean programs like Microsoft @@ -9,12 +9,12 @@ Word or LibreOffice/OpenOffice Writer. These programs are for writing text documents, not for programming. **Programming editors don't support things like bigger font sizes for titles or underlining bits of text**, but instead they have features that are actually useful for programming, -like automatically displaying different things with different colors. +like automatically displaying different things with different colors, +but also highlighting mistakes in the code, and coloring syntax. If you are on Windows or Mac OSX you have probably noticed that your -Python came with an editor called IDLE. We are not going to use it -because it's lacking some important features, and most experienced -programmers (including me) don't use it or recommend it. +Python came with an editor called IDLE. You can use IDLE, but we recommend exploring other options first. + ## Which editor? @@ -22,38 +22,48 @@ The choice of an editor is a very personal thing. There are many editors, and most programmers have a favorite editor that they use for everything and recommend to everyone. -If you aren't sure about which editor you should use, I recommend -Porcupine. It's a simple editor I wrote in Python; it lets you edit -files and it doesn't have too many other featues. [Install it with these -instructions](https://github.com/Akuli/porcupine/wiki/Installing-and-Running-Porcupine), -and then [learn to use it by writing the classic Hello World -program](https://github.com/Akuli/porcupine/wiki/First-Program). Then -you can [skip the rest of this chapter](#editor-or--prompt). - -Note that most other editors come with settings that are not suitable -for writing Python code. _**TODO:** add a link to the old editor setup -tutorial here._ - -Most of these editors lack some important features, they have so many -features that confuse people or they aren't free. You can use these -editors if you like them, but **these editors are BAD for getting -started with programming**: - -- PyCharm -- IDLE -- Emacs -- Gedit -- Nano -- NetBeans -- Notepad -- Pluma -- Spyder -- Vim -- Wingware - -This list doesn't contain all bad editors, but these are editors that -people often try to use. If you know a bad editor and you think I should -mention it here, please [let me know](../contact-me.md). +The editors can be broadly divided into three categories: + +#### The Basic Text Editors +These editors usually come with the operating system. They do not have features like +running code, auto-completion, etc. that make programming easier. They are usually used for relatively simple +text editing. Most programmers do not use these editors for programming. + +A few popular ones in this category are: +- Notepad (Windows) +- Gedit (Linux) +- Notepad ++ (Windows) +- Nano (Linux/Mac OS) + +#### Smart Text Editors +The text editors in this category have features like auto-completion, syntax highlighting, +running and debugging code, highlighting errors, etc. They are relatively easy to learn and have the necessary features +to start your programming journey. + +A few popular ones in this category are: +- Visual Studio Code / VS Code (Windows/Linux/Mac OS) +- IDLE (Usually comes with Python) (Windows/Linux/Mac OS) +- Thonny (Windows/Linux/Mac OS) +- [Porcupine](https://github.com/Akuli/porcupine) (created by the author of this tutorial) (Windows/Linux/Mac OS) +- Geany (Windows/Linux/Mac OS) + +**We recommend that you look into a few of these editors and install your favorite one.** + +#### IDEs and advanced editors +This category of text editors are usually professional grade pieces of software. They are mostly proprietary and paid. They have a steep +learning curve because of how many features they have. +These types of editors are generally not preferred +in the beginning stage. They are meant to be used for writing complex and large pieces of software. + +A few popular ones in this category are: +- Visual Studio (Not be confused with *Visual Studio Code*) (Windows) +- Pycharm (Windows/Linux/Mac OS) +- Vim (Windows/Linux/Mac OS) +- Emacs (Windows/Linux/Mac OS) + +As already mentioned, there are no "right" or "wrong" editors. The preference of an editor +is a personal choice and we recommend trying different editors. +The lists on this page don't contain all editors, but just a few of the most popular ones. ## Editor or `>>>` prompt? @@ -77,9 +87,10 @@ echoes it back, but if you make a file that contains nothing but a *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/exceptions.md b/basics/exceptions.md index 946d4f1..785fb18 100644 --- a/basics/exceptions.md +++ b/basics/exceptions.md @@ -249,9 +249,9 @@ text = input("Enter a number: ") try: number = int(text) except ValueError: - print("'%s' is not a number." % text, file=sys.stderr) + print(f"'{text}' is not a number.", file=sys.stderr) sys.exit(1) -print("Your number doubled is %d." % (number * 2)) +print(f"Your number doubled is {(number * 2)}.") ``` ## Raising exceptions @@ -319,7 +319,7 @@ it's usually better to use `sys.stderr` and `sys.exit`. ## Exception hierarchy Exceptions are organized like this. I made this tree with [this -program](https://github.com/Akuli/classtree/) on Python 3.4. You may +program](https://github.com/Akuli/classtree/) on Python 3.7. You may have more or less exceptions than I have if your Python is newer or older than mine, but they should be mostly similar. @@ -333,6 +333,7 @@ older than mine, but they should be mostly similar. ├── BufferError ├── EOFError ├── ImportError + │ └── ModuleNotFoundError ├── LookupError │ ├── IndexError │ └── KeyError @@ -357,7 +358,9 @@ older than mine, but they should be mostly similar. │ └── TimeoutError ├── ReferenceError ├── RuntimeError - │ └── NotImplementedError + │ ├── NotImplementedError + │ └── RecursionError + ├── StopAsyncIteration ├── StopIteration ├── SyntaxError │ └── IndentationError @@ -449,7 +452,7 @@ def greet(): try: greet() except OSError: - print("Cannot read '%s'!" % filename, file=sys.stderr) + print(f"Cannot read '{filename}'!", file=sys.stderr) if askyesno("Would you like to create a default greeting file?"): with open(filename, 'w') as f: print(default_greeting, file=f) @@ -458,9 +461,10 @@ except OSError: *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/files.md b/basics/files.md index 82705d0..5a8f7dd 100644 --- a/basics/files.md +++ b/basics/files.md @@ -365,9 +365,10 @@ else: *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/getting-started.md b/basics/getting-started.md index 5f482d3..9f00625 100644 --- a/basics/getting-started.md +++ b/basics/getting-started.md @@ -62,9 +62,9 @@ worked just fine. Later we'll learn what `(3, 14)` is. ## Comments -**Comments are text that does nothing.** They can be created by typing a -`#` and then some text after it, and they are useful when our code would -be hard to understand without them. +**Comments are text that don't do anything when they're run.** +They can be created by typing a `#` and then some text after it, +and they are useful when our code would be hard to understand without them. ```python >>> 1 + 2 # can you guess what the result is? @@ -139,7 +139,7 @@ Note that a `#` inside a string doesn't create a comment. ## Using Python as a calculator ```diff ----------- WARNING: This part contains boring math. Be careful! ---------- +---------- WARNING: This part contains boring math. Proceed with caution. ---------- ``` Let's type some math stuff into Python and see what it does. @@ -212,9 +212,10 @@ enough when you need to calculate something. *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/handy-stuff-strings.md b/basics/handy-stuff-strings.md index be89c55..98d5cc4 100644 --- a/basics/handy-stuff-strings.md +++ b/basics/handy-stuff-strings.md @@ -241,82 +241,17 @@ Instead it's recommended to use string formatting. It means putting other things in the middle of a string. Python has multiple ways to format strings. One is not necessarily -better than others, they are just different. Here's a few ways to solve -our problem: +better than others; they each have their own advantages and disadvantages. +In this tutorial, we will focus on f-strings, which is the most common and usually the easiest way. -- `.format()`-formatting, also known as new-style formatting. This - formatting style has a lot of features, but it's a little bit more - typing than `%s`-formatting. - - ```python - >>> "Hello {}.".format(name) - 'Hello Akuli.' - >>> "My name is {} and I'm on the {} channel on {}.".format(name, channel, network) - "My name is Akuli and I'm on the ##learnpython channel on freenode." - >>> - ``` - -- `%s`-formatting, also known as old-style formatting. This has less - features than `.format()`-formatting, but `'Hello %s.' % name` is - shorter and faster to type than `'Hello {}.'.format(name)`. I like - to use `%s` formatting for simple things and `.format` when I need - more powerful features. - - ```python - >>> "Hello %s." % name - 'Hello Akuli.' - >>> "My name is %s and I'm on the %s channel on %s." % (name, channel, network) - "My name is Akuli and I'm on the ##learnpython channel on freenode." - >>> - ``` - - In the second example we had `(name, channel, network)` on the right - side of the `%` sign. It was a tuple, and we'll talk more about them - [later](lists-and-tuples.md#tuples). - - If we have a variable that may be a tuple we need to wrap it in another - tuple when formatting: - - ```python - >>> thestuff = (1, 2, 3) - >>> "we have %s" % thestuff - Traceback (most recent call last): - File "", line 1, in - TypeError: not all arguments converted during string formatting - >>> "we have %s and %s" % ("hello", thestuff) - 'we have hello and (1, 2, 3)' - >>> "we have %s" % (thestuff,) - 'we have (1, 2, 3)' - >>> - ``` - - Here `(thestuff,)` was a tuple that contained nothing but `thestuff`. - -- f-strings are even less typing, but new in Python 3.6. **Use this only if - you know that nobody will need to run your code on Python versions older - than 3.6.** Here the f is short for "format", and the content of the - string is same as it would be with `.format()` but we can use variables - directly. - - ```python - >>> f"My name is {name} and I'm on the {channel} channel on {network}." - "My name is Akuli and I'm on the ##learnpython channel on freenode." - >>> - ``` - -All of these formatting styles have many other features also: +`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. ```python ->>> 'Three zeros and number one: {:04d}'.format(1) -'Three zeros and number one: 0001' ->>> 'Three zeros and number one: %04d' % 1 -'Three zeros and number one: 0001' +>>> f"My name is {name} and I'm on the {channel} channel on {network}." +"My name is Akuli and I'm on the ##learnpython channel on freenode." >>> ``` -If you need to know more about formatting I recommend reading -[this](https://pyformat.info/). - ## Other things We can use `in` and `not in` to check if a string contains another @@ -392,7 +327,7 @@ ValueError: could not convert string to float: 'hello' - Python has many string methods. Use [the documentation](https://docs.python.org/3/library/stdtypes.html#string-methods) - or `help(str)` when you don't rememeber something about them. + or `help(str)` when you don't remember something about them. - String formatting means adding other things to the middle of a string. There are multiple ways to do this in Python. You should know how to use at least one of these ways. @@ -424,14 +359,17 @@ ValueError: could not convert string to float: 'hello' print(message, "!!!") print(message, "!!!") ``` +3. Make a program to ask a string from the user and check if it is a palindrome.
+ (Hint: A string is a palindrome if it is the same when reversed. Google how to reverse a string.) The answers are [here](answers.md#handy-stuff-strings). *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/if.md b/basics/if.md index f509d1e..71655f2 100644 --- a/basics/if.md +++ b/basics/if.md @@ -245,7 +245,20 @@ else: Now the `else` belongs to the `if 1 == 2` part and **it has nothing to do with the `if 1 == 1` part**. On the other hand, the elif version **grouped the multiple ifs together** and the `else` belonged to all of -them. +them. Adding a blank line makes this obvious: + +```python +if 1 == 1: + print("hello") + +if 1 == 2: + print("this is weird") +else: + print("world") +``` + +In general, adding blank lines to appropriate places is a good idea. If +you are asked to "fix code", feel free to add missing blank lines. ## Summary @@ -276,6 +289,7 @@ them. something = input("Enter something: ") if something = 'hello': print("Hello for you too!") + elif something = 'hi' print('Hi there!') else: @@ -298,13 +312,15 @@ them. the user entered the correct password, a wrong password, or nothing at all by pressing Enter without typing anything. + The answers are [here](answers.md#if-else-and-elif). *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/installing-python.md b/basics/installing-python.md index cc693bf..249cc4b 100644 --- a/basics/installing-python.md +++ b/basics/installing-python.md @@ -40,8 +40,9 @@ me](../contact-me.md). ### Linux You already have Python 3, **there's no need to install anything**. You -may also have Python 2, but don't try to remove it. Some of your -programs are probably written in Python 2, so removing Python 2 would +may also have Python 2, but don't try to remove it. +Some of the programs that came with your operating system +are probably written in Python 2, so removing Python 2 would break them. ## Running Python @@ -77,9 +78,10 @@ Now you should have Python installed, and you should be able run it. *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/larger-program.md b/basics/larger-program.md index 521cf3c..4cd0cda 100644 --- a/basics/larger-program.md +++ b/basics/larger-program.md @@ -13,6 +13,8 @@ text displaying function = print text asking function = input ``` +**Save this example file to questions.txt**, we'll need it later. + This might seem useless to you right now, but a program like this can actually be really useful for learning different kinds of things. I originally wrote a program like this to study words of a foreign @@ -80,7 +82,7 @@ def ask_questions(answers): print("Correct!") correct.append(question) else: - print("Wrong! The correct answer is %s." % answer) + print(f"Wrong! The correct answer is {answer}.") wrong.append(question) return (correct, wrong) @@ -179,11 +181,11 @@ def ask_questions(answers): wrong = [] for question, answer in answers.items(): - if input('%s = ' % question).strip() == answer: + if input(f'{question} = ').strip() == answer: print("Correct!") correct.append(question) else: - print("Wrong! The correct answer is %s." % answer) + print(f"Wrong! The correct answer is {answer}.") wrong.append(question) return (correct, wrong) @@ -226,9 +228,10 @@ something else when it's imported. *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/lists-and-tuples.md b/basics/lists-and-tuples.md index 77ea0ca..379d019 100644 --- a/basics/lists-and-tuples.md +++ b/basics/lists-and-tuples.md @@ -141,6 +141,29 @@ We'll talk more about loops [in the next chapter](loops.md). >>> ``` +Another useful thing about lists is **list comprehension**. +It's a handy way to construct a list in single line. It often makes code cleaner, shorter and easier to read. + +```python +>>> numbers = [1,2,3,4,5] +>>> numbers_squared = [number ** 2 for number in numbers] +>>> numbers_squared +[1, 4, 9, 16, 25] +>>> +``` + +Without a list comprehension, doing the same thing looks like this: + +```python +>>> numbers = [1,2,3,4,5] +>>> numbers_squared = [] +>>> for number in numbers: +... numbers_squared.append(number**2) +>>> numbers_squared +[1, 4, 9, 16, 25] +>>> +``` + We can also use slicing and indexing to change the content: ```python @@ -352,9 +375,10 @@ The answers are [here](answers.md#lists-and-tuples). *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/loops.md b/basics/loops.md index 57f6b50..7f693e1 100644 --- a/basics/loops.md +++ b/basics/loops.md @@ -416,7 +416,7 @@ while True: print("I don't know anybody yet.") else: for name in namelist: - print("I know %s!" % name) + print(f"I know {name}!") else: print("I don't understand :(") @@ -426,7 +426,7 @@ while True: ## Exercises -1. This code is supposed to print each number between 1 and 5. Fix it. +1. This code is supposed to print the numbers 1,2,3,4,5. Fix it. ```python things = str([1, 2, 3, 4, 5]) @@ -470,18 +470,37 @@ while True: number = int(number) print(numbers) ``` - +5. Make a program that prints a pyramid like shown below. Ask the user to type the number of rows needed. + ``` + OUTPUT for 5 rows + 1 + 1 2 + 1 2 3 + 1 2 3 4 + 1 2 3 4 5 + ``` + +6. Make a program to get a pyramid like shown below where user can type the number of rows needed. + ``` + OUTPUT for 5 rows + 1 2 3 4 5 + 2 3 4 5 + 3 4 5 + 4 5 + 5 + ``` The answers are [here](answers.md#loops). *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See [LICENSE](../LICENSE). -[Previous](lists-and-tuples.md) | [Next](trey-hunner-zip-and-enumerate.md) | +[Previous](lists-and-tuples.md) | [Next](zip-and-enumerate.md) | [List of contents](../README.md#basics) diff --git a/basics/modules.md b/basics/modules.md index 44cacba..59159cd 100644 --- a/basics/modules.md +++ b/basics/modules.md @@ -28,17 +28,17 @@ gave us? ```python >>> random - + >>> ``` So it's a module, and it comes from a path... but what does all that mean? -Now open the folder that contains your `random.py` is. On my -system it's `/usr/lib/python3.4`, but yours will probably be +Now open the folder that contains your `random.py`. On my +system it's `/usr/lib/python3.7`, but yours will probably be different. To open a folder in your file manager you can press -Windows-R on Windows or Alt+F2 on most GNU/Linux distributions, +Windows-R on Windows or Alt+F2 on most Linux distributions, and just type your path there. I don't have an up-to-date copy of OSX so unfortunately I have no idea what you need to do on OSX. @@ -138,11 +138,11 @@ places that modules are searched from: >>> sys.path ['', - '/usr/lib/python3.4', - '/usr/lib/python3.4/plat-i386-linux-gnu', - '/usr/lib/python3.4/lib-dynload', - '/home/akuli/.local/lib/python3.4/site-packages', - '/usr/local/lib/python3.4/dist-packages', + '/usr/lib/python37.zip', + '/usr/lib/python3.7', + '/usr/lib/python3.7/lib-dynload', + '/home/akuli/.local/lib/python3.7/site-packages', + '/usr/local/lib/python3.7/dist-packages', '/usr/lib/python3/dist-packages'] >>> ``` @@ -234,14 +234,14 @@ hello >>> >>> # information about Python's version, behaves like a tuple >>> sys.version_info -sys.version_info(major=3, minor=4, micro=2, releaselevel='final', serial=0) ->>> sys.version_info[:3] # this is Python 3.4.2 -(3, 4, 2) +sys.version_info(major=3, minor=7, micro=3, releaselevel='final', serial=0) +>>> sys.version_info[:3] # this is Python 3.7.3 +(3, 7, 3) >>> >>> sys.exit() # exit out of Python ``` -**TODO:** why stderr instead of stdout. +**TODO:** why stderr instead of stdout, when to use `sys.stdin.readline()` instead of `input()` `sys.exit()` does the same thing as `sys.exit(0)`. The zero means that the program succeeded, and everything's fine. If our program has an @@ -369,8 +369,8 @@ for thing in things: ``` Measure how long it takes for the user to answer a question. -The `%.2f` rounds to 2 decimals, and you can find more formatting -tricks [here](https://pyformat.info/). +The `{:.2f}` rounds to 2 decimals, and you can find more formatting +tricks [here](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals). ```python import time @@ -381,7 +381,7 @@ end = time.time() difference = end - start if answer == '3': - print("Correct! That took %.2f seconds." % difference) + print(f"Correct! That took {difference:.2f} seconds.") else: print("That's not correct...") ``` @@ -410,7 +410,7 @@ Check what a path points to. import os import sys -print("You are currently in %s." % os.getcwd()) +print(f"You are currently in {os.getcwd()}.") while True: path = input("A path, or nothing at all to quit: ") @@ -461,17 +461,14 @@ then typing in what you want to search for. - [webbrowser](https://pymotw.com/3/webbrowser/): open a web browser from Python -I also use these modules, but they don't come with Python so you'll -need to install them yourself if you want to use them: - -- [appdirs](https://github.com/activestate/appdirs): - an easy way to find out where to put setting files -- [requests](http://docs.python-requests.org/en/master/user/quickstart/): - an awesome networking library +There are also lots of awesome modules that don't come with Python. +You can search for those on the [Python package index](https://pypi.org/), +or PyPI for short. It's often better to find a library that does something +difficult than to spend a lot of time trying to do it yourself. I recommend reading [the official documentation about installing -modules](https://docs.python.org/3/installing/). If you're using -GNU/Linux also read the "Installing into the system Python on Linux" +modules](https://docs.python.org/3/installing/) from PyPI. If you're using +Linux, then also read the "Installing into the system Python on Linux" section at the bottom. ## Summary @@ -491,9 +488,10 @@ section at the bottom. *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/the-way-of-the-program.md b/basics/the-way-of-the-program.md index ebb44bc..7def31a 100644 --- a/basics/the-way-of-the-program.md +++ b/basics/the-way-of-the-program.md @@ -38,9 +38,10 @@ learned everything. *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/trey-hunner-zip-and-enumerate.md b/basics/trey-hunner-zip-and-enumerate.md deleted file mode 100644 index 3a211de..0000000 --- a/basics/trey-hunner-zip-and-enumerate.md +++ /dev/null @@ -1,147 +0,0 @@ -# Trey Hunner: zip and enumerate - -Now we know how [for loops](loops.md#for-loops) work in Python. But -for loops aren't limited to printing each item in a list, they can -do a lot more. - -To be able to understand for loop tricks we need to first know -assigning values to multiple variables at once. It works like this: - -```python ->>> a, b = 1, 2 ->>> a -1 ->>> b -2 ->>> -``` - -We can use `()` and `[]` around these values however we want and -everything will still work the same way. `[]` creates a list, and -`()` creates a tuple. - -```python ->>> [a, b] = (1, 2) ->>> a -1 ->>> b -2 ->>> -``` - -We can also have `[]` or `()` on one side but not on the other -side. - -```python ->>> (a, b) = 1, 2 ->>> a -1 ->>> b -2 ->>> -``` - -Python created a tuple automatically. - -```python ->>> 1, 2 -(1, 2) ->>> -``` - -If we're for looping over a list with pairs of values in it we -could do this: - -```python ->>> items = [('a', 1), ('b', 2), ('c', 3)] ->>> for pair in items: -... a, b = pair -... print(a, b) -... -a 1 -b 2 -c 3 ->>> -``` - -Or we can tell the for loop to unpack it for us. - -```python ->>> for a, b in items: -... print(a, b) -... -a 1 -b 2 -c 3 ->>> -``` - -Now you're ready to read [this awesome looping -tutorial](http://treyhunner.com/2016/04/how-to-loop-with-indexes-in-python/). -Read it now, then come back here and do the exercises. - -## Exercises - -1. Create a program that works like this. Here I entered everything - after the `>` prompt that the program displayed. - - ``` - Enter something, and press Enter without typing anything when you're done. - >hello there - >this is a test - >it seems to work - > - Line 1 is: hello there - Line 2 is: this is a test - Line 3 is: it seems to work - ``` - -2. Create a program that prints all letters from A to Z and a to z - next to each other: - - ``` - A a - B b - C c - ... - X x - Y y - Z z - ``` - - Start your program like this: - - ```python - uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - lowercase = 'abcdefghijklmnopqrstuvwxyz' - ``` - - **Hint:** how do strings behave with `zip`? Try it out on the - `>>>` prompt and see. - -3. Can you make it print the indexes also? - - ``` - 1 A a - 2 B b - 3 C c - ... - 24 X x - 25 Y y - 26 Z z - ``` - -The answers are [here](answers.md). - -*** - -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a -star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). - -You may use this tutorial freely at your own risk. See -[LICENSE](../LICENSE). - -[Previous](loops.md) | [Next](dicts.md) | -[List of contents](../README.md#basics) diff --git a/basics/using-functions.md b/basics/using-functions.md index 123910a..c8255ff 100644 --- a/basics/using-functions.md +++ b/basics/using-functions.md @@ -228,9 +228,10 @@ should work normally. *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/variables.md b/basics/variables.md index 4b9c25b..f1a8030 100644 --- a/basics/variables.md +++ b/basics/variables.md @@ -86,8 +86,9 @@ Variable names are case-sensitive, like many other things in Python. ``` There are also words that cannot be used as variable names -because they have a special meaning. They are called **keywords**, and -we can run `help('keywords')` to see the full list if we want to. +because they are reserved by Python itself and have a special meaning. +They are called **keywords**, and we can run `help('keywords')` +to see the full list if we want to. We'll learn to use most of them later in this tutorial. Trying to use a keyword as a variable name causes a syntax error. @@ -300,9 +301,10 @@ what you are doing. We'll learn more about it later. *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/what-is-programming.md b/basics/what-is-programming.md index ce917a5..269ce3f 100644 --- a/basics/what-is-programming.md +++ b/basics/what-is-programming.md @@ -104,7 +104,7 @@ should you do if you have a problem with the tutorial? 1. Try the example code yourself. 2. Read the code and the explanation for it again. 3. If there's something you haven't seen before in the tutorial and it's - not explained, try to find it from the previous chapters. + not explained, try to find it in the previous chapters. 4. If you can't find what you're looking for or you still have trouble understanding the tutorial or any other problems with the tutorial, please [tell me about it](../contact-me.md). I want to improve this @@ -157,9 +157,10 @@ if you don't understand the code. *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/what-is-true.md b/basics/what-is-true.md index 495aea6..a344239 100644 --- a/basics/what-is-true.md +++ b/basics/what-is-true.md @@ -213,9 +213,10 @@ if value is None: ... # best *** -If you have trouble with this tutorial please [tell me about -it](../contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/basics/zip-and-enumerate.md b/basics/zip-and-enumerate.md new file mode 100644 index 0000000..f1332d3 --- /dev/null +++ b/basics/zip-and-enumerate.md @@ -0,0 +1,248 @@ +# zip and enumerate + +Now we know how [for loops](loops.md#for-loops) work in Python. But +for loops aren't limited to printing each item in a list, they can +do a lot more. + +To be able to understand for loop tricks we need to first know +assigning values to multiple variables at once. It works like this: + +```python +>>> a, b = 1, 2 +>>> a +1 +>>> b +2 +>>> +``` + +We can use `()` and `[]` around these values however we want and +everything will still work the same way. `[]` creates a list, and +`()` creates a tuple. + +```python +>>> [a, b] = (1, 2) +>>> a +1 +>>> b +2 +>>> +``` + +We can also have `[]` or `()` on one side but not on the other +side. + +```python +>>> (a, b) = 1, 2 +>>> a +1 +>>> b +2 +>>> +``` + +Python created a tuple automatically. + +```python +>>> 1, 2 +(1, 2) +>>> +``` + +If we're for looping over a list with pairs of values in it we +could do this: + +```python +>>> items = [('a', 1), ('b', 2), ('c', 3)] +>>> for pair in items: +... a, b = pair +... print(a, b) +... +a 1 +b 2 +c 3 +>>> +``` + +Or we can tell the for loop to unpack it for us. + +```python +>>> for a, b in items: +... print(a, b) +... +a 1 +b 2 +c 3 +>>> +``` + +This feature is often used with Python's built-in `zip()` and `enumerate()` functions. + + +## zip + +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. + +```python +>>> users = ["Tushar", "Aman", "Anurag", "Sohit"] +>>> uids = ["usr122", "usr123", "usr124", "usr125"] +>>> user_details = zip(uids, users) +>>> print(list(user_details)) +[('usr122', 'Tushar'), ('usr123', 'Aman'), ('usr124', 'Anurag'), ('usr125', 'Sohit')] +>>> +``` + +Note that `print(user_details)` doesn't work as expected: + +``` +>>> print(user_details) + +>>> +``` + +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. + +```python +>>> users = ["Tushar", "Aman", "Anurag", "Sohit"] +>>> uids = ["usr122", "usr123", "usr124", "usr125"] +>>> user_details = zip(uids, users) +``` + +If the lists are of different lengths, some items from the end of the longer list will be ignored. +```python +>>> users = ["Tushar", "Aman", "Anurag"] +>>> emails = ["tushar@example.com", "aman@example.com", "anurag@example.com", "sohit@example.com"] +>>> users_contact = zip(users, emails) +>>> print(list(users_contact)) +[('Tushar', 'tushar@example.com'), ('Aman', 'aman@example.com'), ('Anurag', 'anurag@example.com')] +>>> +``` + + +Here the shortest list is `users`, with length 3, so `zip(users, emails)` only takes the first 3 emails. +We do not recommend calling `zip()` with lists of different lengths, because ignoring items is usually not what you intended to do. + +### Using zip in a `for` loop + +It is very common to `for` loop over a `zip()`, and unpack the returned tuples in the `for` loop. +This is why we introduced unpacking in the beginning of this page. +When used this way, there's no need to convert the result of `zip(...)` to a list. + +```python +>>> roll_nums = [20, 25, 28] +>>> students = ["Joe", "Max", "Michel"] +>>> for roll_num, student in zip(roll_nums, students): +... print(f"Roll number of {student} is {roll_num}") +... +Roll number of Joe is 20 +Roll number of Max is 25 +Roll number of Michel is 28 +>>> +``` + +## enumerate + +`enumerate()` is an amazing Built-in function offered by python. When used, gives us the index and the item combined. + +```python +>>> even_nums = [2, 4, 6, 8, 10, 12] +>>> for index, item in enumerate(even_nums): +... print(f"Index of {item} is {index}") +... +Index of 2 is 0 +Index of 4 is 1 +Index of 6 is 2 +Index of 8 is 3 +Index of 10 is 4 +Index of 12 is 5 +>>> +``` + +It is also possible (but more difficult) to do this without `enumerate()`: + +```python +>>> even_nums = [2, 4, 6, 8, 10, 12] +>>> for index in range(0, len(even_nums)): +... print(f"Index of {even_nums[index]} is {index}") +... +Index of 2 is 0 +Index of 4 is 1 +Index of 6 is 2 +Index of 8 is 3 +Index of 10 is 4 +Index of 12 is 5 +>>> +``` + +Here: +* `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. +* `even_nums[index]` prints each element of `even_nums`, because `index` comes from the range of all indexes into that list. + +Because this is complicated to think about and easy to get wrong, it is better to use `enumerate()`. + +## Exercises + +1. Create a program that works like this. Here I entered everything + after the `>` prompt that the program displayed. + + ``` + Enter something, and press Enter without typing anything when you're done. + >hello there + >this is a test + >it seems to work + > + Line 1 is: hello there + Line 2 is: this is a test + Line 3 is: it seems to work + ``` + +2. Create a program that prints all letters from A to Z and a to z + next to each other: + + ``` + A a + B b + C c + ... + X x + Y y + Z z + ``` + + Start your program like this: + + ```python + uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + lowercase = 'abcdefghijklmnopqrstuvwxyz' + ``` + + **Hint:** how do strings behave with `zip`? Try it out on the + `>>>` prompt and see. + +3. Can you make it print the indexes also? + + ``` + 1 A a + 2 B b + 3 C c + ... + 24 X x + 25 Y y + 26 Z z + ``` + +The answers are [here](answers.md). + +*** + +If you have trouble with this tutorial, please +[tell me about it](../contact-me.md) and I'll make this tutorial better, +or [ask for help online](../getting-help.md). +If you like this tutorial, please [give it a +star](../README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). + +You may use this tutorial freely at your own risk. See +[LICENSE](../LICENSE). + +[Previous](loops.md) | [Next](dicts.md) | +[List of contents](../README.md#basics) diff --git a/classes.md b/classes.md index 42ecdc6..0306c61 100644 --- a/classes.md +++ b/classes.md @@ -2,9 +2,10 @@ This file has been moved [here](basics/classes.md). *** -If you have trouble with this tutorial please [tell me about -it](./contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](./contact-me.md) and I'll make this tutorial better, +or [ask for help online](./getting-help.md). +If you like this tutorial, please [give it a star](./README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/common.py b/common.py index 51c22eb..7180739 100644 --- a/common.py +++ b/common.py @@ -122,16 +122,6 @@ def askyesno(question, default=True): print("Please type y, n or nothing at all.") -def slashfix(path): - """Replace / with os.sep.""" - return path.replace('/', os.sep) - - -def slashfix_open(file, mode): - """An easy way to use slashfix() and open() together.""" - return open(slashfix(file), mode) - - @contextlib.contextmanager def backup(filename): """A context manager that backs up a file.""" diff --git a/contact-me.md b/contact-me.md index 0f5aeea..eff6885 100644 --- a/contact-me.md +++ b/contact-me.md @@ -13,14 +13,15 @@ it, there are a few ways to contact me: - Tell me on IRC. - I'm usually on ##learnpython and ##python-friendly on freenode. See + I'm regularly on ##learnpython on libera. See [Getting help](getting-help.md) for instructions to getting there. *** -If you have trouble with this tutorial please [tell me about -it](./contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](./contact-me.md) and I'll make this tutorial better, +or [ask for help online](./getting-help.md). +If you like this tutorial, please [give it a star](./README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/getting-help.md b/getting-help.md index 6080b67..e56e7a2 100644 --- a/getting-help.md +++ b/getting-help.md @@ -3,59 +3,63 @@ When you have a problem with Python, you're not alone! There are many places to ask for help in. +Regardless of where you ask for help, please: +- Don't ask "does someone know ...". Just ask about your problem right away. +- Make your question short. +- Include everything that other people will need to answer your question. + For example, if you are getting an error, include your code and the error message. + + ## IRC -IRC is the oldest chatting service I know, but as of 2017, it's still -in use, and a great way to get help in Python. You don't need to -register anywhere, just click one of the links below and you're good to -go. - -- [##learnpython](https://kiwiirc.com/client/chat.freenode.net/##learnpython) and - [##python-friendly](https://kiwiirc.com/client/chat.freenode.net/##python-friendly) - are beginner-friendly Python support channels. In my experience, - people here tend to understand beginners' problems better, so you - probably want to go to one of these. -- [#python](https://kiwiirc.com/client/chat.freenode.net/#python) is - the official Python channel. If you have questions about advanced - topics or you need help quickly, go there. However, this channel - requires - [registering on freenode](http://www.wikihow.com/Register-a-Nickname-on-Freenode). - -Make your question short. If you want to post a code example that is -more than two lines long, post it [here](http://dpaste.com/) first. +IRC is the oldest chatting service I know, but as of 2022, it's still +in use, and a good way to get help in Python. +An advantage with IRC is that you don't need to create an account to use it. + +To get started, go to https://web.libera.chat/ and type `##learnpython` or `#python` for the channel name. + +- `##learnpython` is a channel where I am regularly, but there's usually only about 20 people there, + so it could be that nobody answers your question, depending on what time it is. + I'm on `##learnpython` at about 7PM to 10PM UTC. + If you see `Akuli` in the user list, that's me :) +- `#python` is an active channel that I don't use much, but someone will likely answer your question pretty quickly. + +If you want to post more than 3 lines of code, +put it to [dpaste.com](https://dpaste.com/) first. Just copy-paste your code to the big text area and click the "Paste it" button, and then post a link to your paste on IRC. +Otherwise every line of your code will appear as a separate message on IRC, +so if your code is 15 lines, just pasting it in will produce 15 different messages. +This would be annoying. + + +## Discord -Do this: +If you have a discord account, you can click the "Explore Public Servers" button at bottom left. - i'm trying to check if this variable equals one but i keep - getting an error http://dpaste.com/yourpaste +![Discord's explore public servers button](images/discord-explore.png) -Don't do this: +You can then search for e.g. Python, and you should find many servers to choose from. +I am currently @Akuli on a server called "The Programmer's Hangout". - HEEEEELP MEEEEEEEEEEEEEEE!!! - File "hello.py", line 3 - if a = b: - ^ - SyntaxError: invalid syntax ## Websites to ask help on Personally, I've never asked a question on any of these sites. Getting help on IRC is much faster. -- [stackoverflow](http://stackoverflow.com/) is a question/answer site +- [stackoverflow](https://stackoverflow.com/) is a question/answer site for programmers. Search for your question first, maybe someone has already asked that and it has been answered. -- At the time of writing this, - [the learnpython subreddit](https://www.reddit.com/r/learnpython/) +- [The learnpython subreddit](https://www.reddit.com/r/learnpython/) is another good place to ask Python questions on. *** -If you have trouble with this tutorial please [tell me about -it](./contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](./contact-me.md) and I'll make this tutorial better, +or [ask for help online](./getting-help.md). +If you like this tutorial, please [give it a star](./README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See diff --git a/images/discord-explore.png b/images/discord-explore.png new file mode 100644 index 0000000..1162495 Binary files /dev/null and b/images/discord-explore.png differ diff --git a/linkcheck.py b/linkcheck.py index 35ced72..2dcd4c5 100755 --- a/linkcheck.py +++ b/linkcheck.py @@ -59,18 +59,17 @@ def check(this_file, target, title, titledict): path = posixpath.join(posixpath.dirname(this_file), target) path = posixpath.normpath(path) - real_path = common.slashfix(path) - if not os.path.exists(real_path): + if not os.path.exists(path): return "doesn't exist" if target.endswith('/'): # A directory. - if not os.path.isdir(real_path): + if not os.path.isdir(path): return "not a directory" else: # A file. - if not os.path.isfile(real_path): + if not os.path.isfile(path): return "not a file" if title is not None and title not in titledict[path]: @@ -82,7 +81,7 @@ def find_titles(filename): """Read titles of a markdown file and return a list of them.""" result = [] - with common.slashfix_open(filename, 'r') as f: + with open(filename, 'r') as f: for line in f: if line.startswith('```'): # it's a code block, let's skip to the end of it to @@ -103,7 +102,7 @@ def find_links(this_file): """ result = [] - with common.slashfix_open(this_file, 'r') as f: + with open(this_file, 'r') as f: for match, lineno in common.find_links(f): target = match.group(2) if '#' in target: @@ -122,7 +121,7 @@ def find_links(this_file): def get_line(filename, lineno): """Return the lineno'th line of a file.""" - with common.slashfix_open(filename, 'r') as f: + with open(filename, 'r') as f: for lineno2, line in enumerate(f, start=1): if lineno == lineno2: return line diff --git a/make-html.py b/make-html.py index a15343d..b40ec3a 100755 --- a/make-html.py +++ b/make-html.py @@ -30,20 +30,26 @@ import argparse import os +import platform import posixpath import shutil import sys import textwrap import webbrowser +if platform.system() == 'Windows': + python = 'py' +else: + python = 'python3' + try: import mistune except ImportError: print("mistune isn't installed.", file=sys.stderr) - print("You can install it like this:") + print("You can install it by running this command on a terminal or ") + print("command prompt:") print() - print(">>> import pip") - print(">>> pip.main(['install', '--user', 'mistune'])") + print(" %s -m pip install mistune" % python) sys.exit(1) try: @@ -86,12 +92,11 @@ class TutorialStyle(pygments.style.Style): """ -def mkdir_slashfix_open(filename, mode): - """Like common.slashfix_open(), but make directories as needed.""" - real_filename = common.slashfix(filename) - directory = os.path.dirname(real_filename) +def mkdir_and_open(filename, mode): + """Like open(), but make directories as needed.""" + directory = os.path.dirname(filename) os.makedirs(directory, exist_ok=True) - return open(real_filename, mode) + return open(filename, mode) def fix_filename(filename): @@ -107,7 +112,7 @@ def fix_filename(filename): return filename -class TutorialRenderer(mistune.Renderer): +class TutorialRenderer(mistune.HTMLRenderer): def __init__(self, pygments_style): super().__init__() @@ -221,8 +226,7 @@ def main(): if pygments is None: print("Pygments isn't installed. You can install it like this:") print() - print(">>> import pip") - print(">>> pip.main(['install', '--user', 'pygments'])") + print(" %s -m pip install pygments" % python) print() print("You can also continue without Pygments, but the code examples") print("will not be colored.") @@ -247,7 +251,7 @@ def main(): htmlfile = posixpath.join(args.outdir, fixed_file) print(' %-30.30s --> %-30.30s' % (markdownfile, htmlfile), end='\r') - with common.slashfix_open(markdownfile, 'r') as f: + with open(markdownfile, 'r') as f: markdown = f.read() renderer = TutorialRenderer(args.pygments_style) body = mistune.markdown(markdown, renderer=renderer) @@ -259,7 +263,7 @@ def main(): body=body, stylefile=stylefile, ) - with mkdir_slashfix_open(htmlfile, 'w') as f: + with mkdir_and_open(htmlfile, 'w') as f: print(html, file=f) print() diff --git a/update-ends.py b/update-ends.py index 820ef6a..9b2d1ef 100755 --- a/update-ends.py +++ b/update-ends.py @@ -35,9 +35,10 @@ END_TEMPLATE = """\ -If you have trouble with this tutorial please [tell me about -it]({toplevel}/contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it]({toplevel}/contact-me.md) and I'll make this tutorial better, +or [ask for help online]({toplevel}/getting-help.md). +If you like this tutorial, please [give it a star]({toplevel}/README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See @@ -85,7 +86,7 @@ def update_end(filename, end): separator. """ end = '\n***\n\n' + end - with common.slashfix_open(filename, 'r') as f: + with open(filename, 'r') as f: content = f.read() if content.endswith(end): # No need to do anything. @@ -96,11 +97,11 @@ def update_end(filename, end): # We need to remove the old ending first. print(" Removing old end:", filename) where = content.index('\n***\n') - with common.slashfix_open(filename, 'w') as f: + with open(filename, 'w') as f: f.write(content[:where]) print(" Adding end:", filename) - with common.slashfix_open(filename, 'a') as f: + with open(filename, 'a') as f: f.write(end) diff --git a/what-next.md b/what-next.md index bd2de84..8437d95 100644 --- a/what-next.md +++ b/what-next.md @@ -31,9 +31,10 @@ is a way to create generators *** -If you have trouble with this tutorial please [tell me about -it](./contact-me.md) and I'll make this tutorial better. If you -like this tutorial, please [give it a +If you have trouble with this tutorial, please +[tell me about it](./contact-me.md) and I'll make this tutorial better, +or [ask for help online](./getting-help.md). +If you like this tutorial, please [give it a star](./README.md#how-can-i-thank-you-for-writing-and-sharing-this-tutorial). You may use this tutorial freely at your own risk. See