├── .gitignore ├── Makefile ├── README.md ├── chapters ├── async.md ├── basic-datatypes.md ├── classes.md ├── coroutines.md ├── dictionaries.md ├── functions.md ├── generators.md ├── installation.md ├── introduction.md ├── iterators.md ├── lists.md └── loops.md ├── diagrams ├── consumers_pipeline.txt ├── coroutine_pipeline.txt └── instructions.txt ├── images ├── consumers_pipeline.png ├── coroutine_pipeline.png ├── pip_windows.jpg ├── python_linux.png ├── python_macos.png ├── python_windows.jpg ├── python_windows2.jpg ├── python_windows3.jpg └── python_windows4.jpg ├── metadata.yaml └── tex └── preamble.tex /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | 4 | # Releases 5 | *.pdf 6 | *.epub 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | chapters = \ 2 | chapters/introduction.md \ 3 | chapters/installation.md \ 4 | chapters/basic-datatypes.md \ 5 | chapters/lists.md \ 6 | chapters/functions.md \ 7 | chapters/loops.md \ 8 | chapters/dictionaries.md \ 9 | chapters/classes.md \ 10 | chapters/iterators.md \ 11 | chapters/generators.md \ 12 | chapters/coroutines.md \ 13 | chapters/async.md \ 14 | 15 | options = metadata.yaml --highlight-style tango --number-sections 16 | 17 | all: epub pdf 18 | 19 | epub: 20 | pandoc -o full-speed-python.epub $(options) $(chapters) 21 | 22 | pdf: 23 | pandoc -o full-speed-python.pdf -H tex/preamble.tex $(options) $(chapters) 24 | 25 | clean: 26 | rm *.epub *.pdf 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Full Speed Python 2 | 3 | ### About 4 | 5 | This book aims to teach the Python programming language using a practical approach. Its method is quite simple: after a short introduction to each topic, the reader is invited to learn more by solving the proposed exercises. 6 | 7 | These exercises have been used extensively in my web development and distributed computing classes at the Superior School of Technology of Setúbal. With these exercises, most students are up to speed with Python in less than a month. In fact, students of the distributed computing course, taught in the second year of the software engineering degree, become familiar with Python's syntax in two weeks and are able to implement a distributed client-server application with sockets in the third week. 8 | 9 | The source of this book is available on github (https://github.com/joaoventura/full-speed-python). I welcome any pull requests to correct misspellings, suggest new exercises or to provide clarification of the current content. 10 | 11 | ### How to get the ebook? 12 | 13 | Pdf and epub files can be downloaded from: https://jventura.gumroad.com/l/fullspeedpython. The ebooks are free (as in free beer!), but if you want to support my work and allow me to improve it, you can set any other price. 14 | 15 | ## Building 16 | 17 | Run `make pdf` or `make epub` to build the books. 18 | 19 | This project uses [pandoc](http://pandoc.org/) to build the books. The pdf file is built with pdflatex, so you may need to download a latex distribution. 20 | -------------------------------------------------------------------------------- /chapters/async.md: -------------------------------------------------------------------------------- 1 | # Asynchronous programming 2 | 3 | So far we have been doing *synchronous programming*. Synchronous program execution is quite simple: a program starts at the first line, then each line is executed until the program reaches the end. Each time a function is called, the program waits for the function to return before continuing to the next line. 4 | 5 | In asynchronous programming, the execution of a function is usually non-blocking. In other words, each time you call a function it returns immediately. However, that function does not necessarily gets executed right way. Instead, there is usually a mechanism (called the "scheduler") which is responsible for the future execution of the function. 6 | 7 | The problem with asynchronous programming is that a program may end before any asynchronous function starts. A common solution for this is for asynchronous functions to return "futures" or "promises". These are objects that represent the state of execution of an async function. Finally, asynchronous programming frameworks typically have mechanisms to block or wait for those async functions to end based on those "future" objects. 8 | 9 | Since Python 3.6, the "asyncio" module combined with the *async* and *await* keyword allows us to implement what is called *co-operative multitasking programs*. In this type of programming, a coroutine function voluntarily yields control to another coroutine function when idle or when waiting for some input. 10 | 11 | Consider the following asynchronous function that squares a number and sleeps for one second before returning. Asynchronous functions are declared with **async def**. Ignore the **await** keyword for now: 12 | 13 | ```Python 14 | import asyncio 15 | 16 | async def square(x): 17 | print('Square', x) 18 | await asyncio.sleep(1) 19 | print('End square', x) 20 | return x * x 21 | 22 | # Create event loop 23 | loop = asyncio.get_event_loop() 24 | 25 | # Run async function and wait for completion 26 | results = loop.run_until_complete(square(1)) 27 | print(results) 28 | 29 | # Close the loop 30 | loop.close() 31 | ``` 32 | 33 | The event loop () is, among other things, the Python mechanism that schedules the execution of asynchronous functions. We use the loop to run the function until completion. This is a synchronizing mechanism that makes sure the next print statement doesn't execute until we have some results. 34 | 35 | The previous example is not a good example of asynchronous programming because we don't need that much complexity to execute only one function. However, imagine that you would need to execute the `square(x)` function three times, like this: 36 | 37 | ```python 38 | square(1) 39 | square(2) 40 | square(3) 41 | ``` 42 | 43 | Since the `square()` function has a sleep function inside, the total execution time of this program would be 3 seconds. However, given that the computer is going to be idle for a full second each time the function is executed, why can't we start the next call while the previous is sleeping? Here's how we do it: 44 | 45 | ```Python 46 | # Run async function and wait for completion 47 | results = loop.run_until_complete(asyncio.gather( 48 | square(1), 49 | square(2), 50 | square(3) 51 | )) 52 | print(results) 53 | ``` 54 | 55 | Basically, we use ``asyncio.gather(*tasks)`` to inform the loop to wait for all tasks to finish. Since the coroutines will start at almost the same time, the program will run for only 1 second. Asyncio **gather()** won't necessarily run the coroutines by order although it will return an ordered list of results. 56 | 57 | ```Python 58 | $ python3 python_async.py 59 | Square 2 60 | Square 1 61 | Square 3 62 | End square 2 63 | End square 1 64 | End square 3 65 | [1, 4, 9] 66 | ``` 67 | 68 | Sometimes results may be needed as soon as they are available. For that we can use a second coroutine that deals with each result using ``asyncio.as_completed()``: 69 | 70 | ```Python 71 | (...) 72 | 73 | async def when_done(tasks): 74 | for res in asyncio.as_completed(tasks): 75 | print('Result:', await res) 76 | 77 | loop = asyncio.get_event_loop() 78 | loop.run_until_complete(when_done([ 79 | square(1), 80 | square(2), 81 | square(3) 82 | ])) 83 | ``` 84 | 85 | This will print something like: 86 | 87 | ```Python 88 | Square 2 89 | Square 3 90 | Square 1 91 | End square 3 92 | Result: 9 93 | End square 1 94 | Result: 1 95 | End square 2 96 | Result: 4 97 | ``` 98 | 99 | Finally, async coroutines can call **other async coroutine functions** with the **await** keyword: 100 | 101 | ```Python 102 | async def compute_square(x): 103 | await asyncio.sleep(1) 104 | return x * x 105 | 106 | async def square(x): 107 | print('Square', x) 108 | res = await compute_square(x) 109 | print('End square', x) 110 | return res 111 | ``` 112 | 113 | ## Exercises with asyncio 114 | 115 | 1. Implement an asynchronous coroutine function to add two variables and sleep for the duration of the sum. Use the asyncio loop to call the function with two numbers. 116 | 117 | 2. Change the previous program to schedule the execution of two calls to the sum function. 118 | -------------------------------------------------------------------------------- /chapters/basic-datatypes.md: -------------------------------------------------------------------------------- 1 | # Numbers and strings 2 | 3 | In this chapter we will work with the most basic datatypes, numbers and strings. Start your Python REPL and write the following: 4 | 5 | ```Python 6 | >>> a = 2 7 | >>> type(a) 8 | 9 | >>> b = 2.5 10 | >>> type(b) 11 | 12 | ``` 13 | 14 | Basically, you are declaring two variables (named "a" and "b") which will hold some numbers: variable "a" is an integer number while variable "b" is a real number. We can now use our variables or any other numbers to do some calculations: 15 | 16 | ```Python 17 | >>> a + b 18 | 4.5 19 | >>> (a + b) * 2 20 | 9.0 21 | >>> 2 + 2 + 4 - 2/3 22 | 7.333333333333333 23 | ``` 24 | 25 | Python also has support for string datatypes. Strings are sequences of characters (like words) and can be defined using single or double quotes: 26 | 27 | ```Python 28 | >>> hi = "hello" 29 | >>> hi 30 | 'hello' 31 | >>> bye = 'goodbye' 32 | >>> bye 33 | 'goodbye' 34 | ``` 35 | 36 | You can add strings to concatenate them but you can not mix different datatypes, such as strings and integers. 37 | 38 | ```Python 39 | >>> hi + "world" 40 | 'helloworld' 41 | >>> "Hello" + 3 42 | Traceback (most recent call last): 43 | File "", line 1, in 44 | TypeError: must be str, not int 45 | ``` 46 | 47 | However, multiplication works as repetition: 48 | 49 | ```Python 50 | >>> "Hello" * 3 51 | 'HelloHelloHello' 52 | ``` 53 | 54 | ## Exercises with numbers 55 | 56 | 1. Try the following mathematical calculations and guess what is happening: \((3 / 2)\), \((3 // 2)\), \((3 \% 2)\), \((3**2)\). 57 | 58 | Suggestion: check the Python library reference at . 59 | 60 | 2. Calculate the average of the following sequences of numbers: (2, 4), (4, 8, 9), (12, 14/6, 15) 61 | 62 | 3. The volume of a sphere is given by (4/3 * pi * r^3). Calculate the volume of a sphere of radius 5. Suggestion: create a variable named "pi" with the value of 3.1415. 63 | 64 | 4. Use the modulo operator (%) to check which of the following numbers is even or odd: (1, 5, 20, 60/7). 65 | 66 | Suggestion: the remainder of \(x/2\) is always zero when \(x\) is even. 67 | 68 | 5. Find some values for \(x\) and \(y\) such that \(x < 1/3 < y\) returns "True" on the Python REPL. Suggestion: try \(0 < 1/3 < 1\) on the REPL. 69 | 70 | ## Exercises with strings 71 | 72 | Using the Python documentation on strings (), solve the following exercises: 73 | 74 | 1. Initialize the string "abc" on a variable named "s": 75 | 76 | 1. Use a function to get the length of the string. 77 | 78 | 2. Write the necessary sequence of operations to transform the string "abc" in "aaabbbccc". Suggestion: Use string concatenation and string indexes. 79 | 80 | 2. Initialize the string "aaabbbccc" on a variable named "s": 81 | 82 | 1. Use a function that allows you to find the first occurence of "b" in the string, and the first occurence of "ccc". 83 | 84 | 2. Use a function that allows you to replace all occurences of "a" to "X", and then use the same function to change only the first occurence of "a" to "X". 85 | 86 | 3. Starting from the string "aaa bbb ccc", what sequences of operations do you need to arrive at the following strings? You can use the "replace" function. 87 | 88 | 1. "AAA BBB CCC" 89 | 90 | 2. "AAA bbb CCC" 91 | -------------------------------------------------------------------------------- /chapters/classes.md: -------------------------------------------------------------------------------- 1 | # Classes 2 | 3 | In object oriented programming (OOP), a class is a structure that allows to group together a set of properties (called attributes) and functions (called methods) to manipulate those properties. Take the following class that defines a person with properties "name" and "age" and the "greet" method. 4 | 5 | ```Python 6 | class Person: 7 | 8 | def __init__(self, name, age): 9 | self.name = name 10 | self.age = age 11 | 12 | def greet(self): 13 | print("Hello, my name is %s!" % self.name) 14 | ``` 15 | 16 | Most classes will need the constructor method ("\_\_init\_\_") to initialize the class’s attributes. In the previous case the constructor of the class receives the person’s name and age and stores that information in the class’s instance (referenced by the *self* keyword). Finally, "greet" method prints the name of the person as stored in a specific class instance (object). 17 | 18 | Class instances are used through the instantiation of objects. Here’s how we can instantiate two objects: 19 | 20 | ```Python 21 | >>> a = Person("Peter", 20) 22 | >>> b = Person("Anna", 19) 23 | 24 | >>> a.greet() 25 | Hello, my name is Peter! 26 | >>> b.greet() 27 | Hello, my name is Anna! 28 | 29 | >>> print(a.age) # We can also access the attributes of an object 30 | 20 31 | ``` 32 | 33 | ## Exercises with classes 34 | 35 | Use the Python documentation on classes at to solve the following exercises. 36 | 37 | 1. Implement a class named "Rectangle" to store the coordinates of a rectangle given the top-left corner (x1, y1) and the bottom-right corner (x2, y2). 38 | 39 | 2. Implement the class constructor with the parameters (x1, y1, x2, y2) and store them in the class instance using the "self" keyword. 40 | 41 | 3. Implement the "width()" and "height()" methods which return, respectively, the width and height of a rectangle. Create two objects, instances of "Rectangle" to test the calculations. 42 | 43 | 4. Implement the method "area" to return the area of the rectangle (width\*height). 44 | 45 | 5. Implement the method "circumference" to return the perimeter of the rectangle (2\*width + 2\*height). 46 | 47 | 6. Do a print of one of the objects created to test the class. Implement the "\_\_str\_\_" method such that when you print one of the objects it print the coordinates as (x1, y1)(x2, y2). 48 | 49 | ## Class inheritance 50 | 51 | In object oriented programming, inheritance is one of the forms in which a subclass can inherit the attributes and methods of another class, allowing it to rewrite some of the super class’s functionalities. For instance, from the "Person" class above we could create a subclass to keep people with 10 years of age: 52 | 53 | ```Python 54 | class TenYearOldPerson(Person): 55 | 56 | def __init__(self, name): 57 | super().__init__(name, 10) 58 | 59 | def greet(self): 60 | print("I don't talk to strangers!!") 61 | ``` 62 | 63 | The indication that the "TenYearOldPerson" class is a subclass of "Person" is given on the first line. Then, we rewrote the constructor of the subclass to only receive the name of the person, but we will eventually call the super class’s constructor with the name of the 10-year-old and the age hardcoded as 10. Finally we reimplemented the "greet" method. 64 | 65 | ## Exercises with inheritance 66 | 67 | Use the "Rectangle" class as implemented above for the following exercises: 68 | 69 | 1. Create a "Square" class as subclass of "Rectangle". 70 | 71 | 2. Implement the "Square" constructor. The constructor should have only the x1, y1 coordinates and the size of the square. Notice which arguments you’ll have to use when you invoke the "Rectangle" constructor when you use "super". 72 | 73 | 3. Instantiate two objects of "Square", invoke the area method and print the objects. Make sure that all calculations are returning correct numbers and that the coordinates of the squares are consistent with the size of the square used as argument. 74 | -------------------------------------------------------------------------------- /chapters/coroutines.md: -------------------------------------------------------------------------------- 1 | # Coroutines 2 | 3 | Python coroutines are similar to generators but instead of producing data, coroutines are mostly used as data consumers. In other words, coroutines are functions that are resumed everytime a value is sent using the `send` method. 4 | 5 | The trick with coroutines is the use of the `yield` keyword on the right side of an assignment expression. Here's an example of a coroutine that just prints the values that are sent to it: 6 | 7 | ```Python 8 | def coroutine(): 9 | print('My coroutine') 10 | while True: 11 | val = yield 12 | print('Got', val) 13 | 14 | >>> co = coroutine() 15 | >>> next(co) 16 | My coroutine 17 | >>> co.send(1) 18 | Got 1 19 | >>> co.send(2) 20 | Got 2 21 | >>> co.send(3) 22 | Got 3 23 | ``` 24 | 25 | The initial call to `next` is required to move the coroutine forward. You can see that it executes the print statement. Eventually, the function reaches the `yield` expression where it will wait to be resumed. Then, everytime a value is sent (with `send`), the coroutine function resumes from the `yield`, copies the value to **val** and prints it. 26 | 27 | Coroutines can be closed with the `close()` method. 28 | 29 | ```Python 30 | >>> co.close() 31 | >>> co.send(4) 32 | Traceback (most recent call last): 33 | File "", line 1, in 34 | StopIteration 35 | ``` 36 | 37 | ## Exercises with coroutines 38 | 39 | 1. Create a coroutine named "square" that prints the square of any sent value. 40 | 41 | 2. Implement the "minimize" coroutine that keeps and prints the minimum value that is sent to the function. 42 | 43 | ## Pipelines 44 | 45 | Coroutines can be used to implement data pipelines where one coroutine will send data to the next coroutine in the pipeline. Coroutines push data into the pipeline using the `send()` method. 46 | 47 | ![](images/coroutine_pipeline.png) 48 | 49 | Here's an example of a small pipeline where the values sent to the producer coroutine are squared and sent to the consumer coroutine for printing: 50 | 51 | ```Python 52 | def producer(consumer): 53 | print("Producer ready") 54 | while True: 55 | val = yield 56 | consumer.send(val * val) 57 | 58 | def consumer(): 59 | print("Consumer ready") 60 | while True: 61 | val = yield 62 | print('Consumer got', val) 63 | ``` 64 | 65 | As above, coroutines must be "primed" with `next` before any value can be sent. 66 | 67 | ```Python 68 | >>> cons = consumer() 69 | >>> prod = producer(cons) 70 | >>> next(prod) 71 | Producer ready 72 | >>> next(cons) 73 | Consumer ready 74 | 75 | >>> prod.send(1) 76 | Consumer got 1 77 | >>> prod.send(2) 78 | Consumer got 4 79 | >>> prod.send(3) 80 | Consumer got 9 81 | ``` 82 | 83 | Also, with coroutines, data can be sent to multiple destinations.The following example implements two consumers where the first only prints numbers in 0..10 and the second only print numbers in 10..20: 84 | 85 | ```Python 86 | def producer(consumers): 87 | print("Producer ready") 88 | try: 89 | while True: 90 | val = yield 91 | for consumer in consumers: 92 | consumer.send(val * val) 93 | except GeneratorExit: 94 | for consumer in consumers: 95 | consumer.close() 96 | 97 | def consumer(name, low, high): 98 | print("%s ready" % name) 99 | try: 100 | while True: 101 | val = yield 102 | if low < val < high: 103 | print('%s got' % name, val) 104 | except GeneratorExit: 105 | print("%s closed" % name) 106 | ``` 107 | 108 | As before, coroutines must be "primed" before any value can be sent. 109 | 110 | ```Python 111 | >>> con1 = consumer('Consumer 1', 00, 10) 112 | >>> con2 = consumer('Consumer 2', 10, 20) 113 | >>> prod = producer([con1, con2]) 114 | 115 | >>> next(prod) 116 | Producer ready 117 | >>> next(con1) 118 | Consumer 1 ready 119 | >>> next(con2) 120 | Consumer 2 ready 121 | 122 | >>> prod.send(1) 123 | Consumer 1 got 1 124 | >>> prod.send(2) 125 | Consumer 1 got 4 126 | >>> prod.send(3) 127 | Consumer 1 got 9 128 | >>> prod.send(4) 129 | Consumer 2 got 16 130 | 131 | >>> prod.close() 132 | Consumer 1 closed 133 | Consumer 2 closed 134 | ``` 135 | 136 | The data is sent to all consumers but only the second executes the print statement. Notice the use of the `GeneratorExit` exception. Sometimes it can be useful to catch the exception and inform the downstream coroutines that the pipeline is no longer useful. 137 | 138 | ![](images/consumers_pipeline.png) 139 | 140 | ## Exercises with coroutine pipelines 141 | 142 | 1. Implement a producer-consumer pipeline where the values squared by the producer are sent to two consumers. One should store and print the minimum value sent so far and the other the maximum value. 143 | 144 | 2. Implement a producer-consumer pipeline where the values squared by the producer are dispatched to two consumers, one at a time. The first value should be sent to consumer 1, the second value to consumer 2, third value to consumer 1 again, and so on. Closing the producer should force the consumers to print a list with the numbers that each one obtained. 145 | -------------------------------------------------------------------------------- /chapters/dictionaries.md: -------------------------------------------------------------------------------- 1 | # Dictionaries 2 | 3 | In this chapter we will work with Python dictionaries. Dictionaries are data structures that indexes values by a given key (key-value pairs). The following example shows a dictionary that indexes students ages by name. 4 | 5 | ```Python 6 | ages = { 7 | "Peter": 10, 8 | "Isabel": 11, 9 | "Anna": 9, 10 | "Thomas": 10, 11 | "Bob": 10, 12 | "Joseph": 11, 13 | "Maria": 12, 14 | "Gabriel": 10, 15 | } 16 | 17 | >>> print(ages["Peter"]) 18 | 10 19 | ``` 20 | 21 | It is possible to iterate over the contents of a dictionary using "items", like this: 22 | 23 | ```Python 24 | >>> for name, age in ages.items(): 25 | ... print(name, age) 26 | ... 27 | Peter 10 28 | Isabel 11 29 | Anna 9 30 | Thomas 10 31 | Bob 10 32 | Joseph 11 33 | Maria 12 34 | Gabriel 10 35 | ``` 36 | 37 | However, dictionary keys don’t necessarily need to be strings but can be any [immutable](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) object: 38 | 39 | ```Python 40 | d = { 41 | 0: [0, 0, 0], 42 | 1: [1, 1, 1], 43 | 2: [2, 2, 2], 44 | } 45 | 46 | >>> d[2] 47 | [2, 2, 2] 48 | ``` 49 | 50 | And you can also use other dictionaries as values: 51 | 52 | ```Python 53 | students = { 54 | "Peter": {"age": 10, "address": "Lisbon"}, 55 | "Isabel": {"age": 11, "address": "Sesimbra"}, 56 | "Anna": {"age": 9, "address": "Lisbon"}, 57 | } 58 | 59 | >>> students['Peter'] 60 | {'age': 10, 'address': 'Lisbon'} 61 | >>> students['Peter']['address'] 62 | 'Lisbon' 63 | ``` 64 | 65 | This is quite useful to structure hierarchical information. 66 | 67 | ## Exercises with dictionaries 68 | 69 | Use the Python documentation at to solve the following exercises. 70 | 71 | Take the following Python dictionary: 72 | 73 | ages = { 74 | "Peter": 10, 75 | "Isabel": 11, 76 | "Anna": 9, 77 | "Thomas": 10, 78 | "Bob": 10, 79 | "Joseph": 11, 80 | "Maria": 12, 81 | "Gabriel": 10, 82 | } 83 | 84 | 1. How many students are in the dictionary? Search for the "len" function. 85 | 86 | 2. Implement a function that receives the "ages" dictionary as parameter and returns the average age of the students. Traverse all items on the dictionary using the "items" method as above. 87 | 88 | 3. Implement a function that receives the "ages" dictionary as parameter and returns the name of the oldest student. 89 | 90 | 4. Implement a function that receives the "ages" dictionary and a number "n" and returns a new dict where each student is \(n\) years older. For instance, *new_ages(ages, 10)* returns a copy of "ages" where each student is 10 years older. 91 | 92 | ## Exercises with sub-dictionaries 93 | 94 | Take the following dictionary: 95 | 96 | students = { 97 | "Peter": {"age": 10, "address": "Lisbon"}, 98 | "Isabel": {"age": 11, "address": "Sesimbra"}, 99 | "Anna": {"age": 9, "address": "Lisbon"}, 100 | } 101 | 102 | 1. How many students are in the "students" dict? Use the appropriate function. 103 | 104 | 2. Implement a function that receives the students dict and returns the average age. 105 | 106 | 3. Implement a function that receives the students dict and an address, and returns a list with names of all students whose address matches the address in the argument. For instance, invoking "find_students(students, ’Lisbon’)" should return Peter and Anna. 107 | -------------------------------------------------------------------------------- /chapters/functions.md: -------------------------------------------------------------------------------- 1 | # Modules and functions 2 | 3 | In this chapter we will talk about modules and functions. A function is a block of code that is used to perform a single action. A module is a Python file containing variables, functions and many more things. 4 | 5 | Start up your Python REPL and let’s use the "math" module which provides access to mathematical functions: 6 | 7 | ```Python 8 | >>> import math 9 | >>> math.cos(0.0) 10 | 1.0 11 | >>> math.radians(275) 12 | 4.799655442984406 13 | ``` 14 | 15 | Functions are sequences of instructions that are executed when the function is invoked. The following defines the "do\_hello" function that prints two messages when invoked: 16 | 17 | ```Python 18 | >>> def do_hello(): 19 | ... print("Hello") 20 | ... print("World") 21 | ... 22 | >>> do_hello() 23 | Hello 24 | World 25 | ``` 26 | 27 | Make sure that you insert a tab before both print expressions in the previous function. Tabs and spaces in Python are relevant and define that a block of code is somewhat dependent on a previous instruction. For instance, the print expressions are "inside" the "do\_hello" function therefore must have a tab. 28 | 29 | Functions can also receive parameters and return values (using the "return" keyword): 30 | 31 | ```Python 32 | >>> def add_one(val): 33 | ... print("Function got value", val) 34 | ... return val + 1 35 | ... 36 | >>> value = add_one(1) 37 | Function got value 1 38 | >>> value 39 | 2 40 | ``` 41 | 42 | ## Exercises with the math module 43 | 44 | Use the Python documentation about the math module () to solve the following exercises: 45 | 46 | 1. Find the greatest common divisor of the following pairs of numbers: (15, 21), (152, 200), (1988, 9765). 47 | 48 | 2. Compute the base-2 logarithm of the following numbers: 0, 1, 2, 6, 9, 15. 49 | 50 | 3. Use the "input" function to ask the user for a number and show the result of the sine, cosine and tangent of the number. Make sure that you convert the user input from string to a number (use the int() or the float() function). 51 | 52 | ## Exercises with functions 53 | 54 | 1. Implement the "add2" function that receives two numbers as arguments and returns the sum of the numbers. Then implement the "add3" function that receives and sums 3 parameters. 55 | 56 | 2. Implement a function that returns the greatest of two numbers given as parameters. Use the "if" statement to compare both numbers: . 57 | 58 | 3. Implement a function named "is\_divisible" that receives two parameters (named "a" and "b") and returns true if "a" can be divided by "b" or false otherwise. A number is divisible by another when the remainder of the division is zero. Use the modulo operator ("%"). 59 | 60 | 4. Create a function named "average" that computes the average value of a list passed as parameter to the function. Use the "sum" and "len" functions. 61 | 62 | ## Recursive functions 63 | 64 | In computer programming, a recursive function is simply a function that calls itself. For instance take the factorial function. 65 | 66 | \begin{equation} 67 | f(x)=\begin{cases} 68 | 1, & \text{if $x=0$}.\\ 69 | x \times f(x-1), & \text{otherwise}. 70 | \end{cases} 71 | \end{equation} 72 | 73 | As an example, take the factorial of 5: 74 | 75 | \begin{equation} 76 | \begin{split} 77 | 5! &= 5 \times 4! \\ 78 | &= 5 \times 4 \times 3! \\ 79 | &= 5 \times 4 \times 3 \times 2! \\ 80 | &= 5 \times 4 \times 3 \times 2 \times 1 \\ 81 | &= 120 82 | \end{split} 83 | \end{equation} 84 | 85 | Basically, the factorial of 5 is 5 times the factorial of 4, etc. Finally, the factorial of 1 (or of zero) is 1 which breaks the recursion. In Python we could write the following recursive function: 86 | 87 | ```Python 88 | def factorial(x): 89 | if x == 0: 90 | return 1 91 | else: 92 | return x * factorial(x-1) 93 | ``` 94 | 95 | The trick with recursive functions is that there must be a "base" case where the recursion must end and a recursive case that iterates towards the base case. In the case of factorial we know that the factorial of zero is one, and the factorial of a number greater that zero will depend on the factorial of the previous number until it reaches zero. 96 | 97 | ## Exercises with recursive functions 98 | 99 | 1. Implement the factorial function and test it with several different values. Cross-check with a calculator. 100 | 101 | 2. Implement a recursive function to compute the sum of the \(n\) first integer numbers (where \(n\) is a function parameter). Start by thinking about the base case (the sum of the first 0 integers is?) and then think about the recursive case. 102 | 103 | 3. The Fibonnaci sequence is a sequence of numbers in which each number of the sequence matches the sum of the previous two terms. Given the following recursive definition implement \(fib(n)\). 104 | 105 | \begin{equation} 106 | fib(n)=\begin{cases} 107 | 0, & \text{if $n=0$}.\\ 108 | 1, & \text{if $n=1$}.\\ 109 | fib(n-1) + fib(n-2), & \text{otherwise}. 110 | \end{cases} 111 | \end{equation} 112 | 113 | Check your results for the first numbers of the sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... 114 | -------------------------------------------------------------------------------- /chapters/generators.md: -------------------------------------------------------------------------------- 1 | # Generators 2 | 3 | If you read the previous chapter, you know that iterators are objects that are regularly used with "for" loops. In other words, iterators are objects that implement the iteration protocol. A Python generator is a convenient way to implement an iterator. Instead of a class, a generator is a function which returns a value each time the "yield" keyword is used. Here’s an example of a generator to count the values between two numbers: 4 | 5 | ```Python 6 | def myrange(a, b): 7 | while a < b: 8 | yield a 9 | a += 1 10 | ``` 11 | 12 | Like iterators, generators can be used with the "for" loop: 13 | 14 | ```Python 15 | >>> for value in myrange(1, 4): 16 | ... print(value) 17 | ... 18 | 1 19 | 2 20 | 3 21 | ``` 22 | 23 | Under the hood, generators behave similarly to iterators: 24 | 25 | ```Python 26 | >>> seq = myrange(1,3) 27 | >>> next(seq) 28 | 1 29 | >>> next(seq) 30 | 2 31 | >>> next(seq) 32 | Traceback (most recent call last): 33 | File "", line 1, in 34 | StopIteration 35 | ``` 36 | 37 | The interesting thing about generators is the "yield" keyword. The "yield" keyword works much like the "return" keyword, but unlike "return", it allows the function to eventually resume its execution. In other words, each time the next value of a generator is needed, Python wakes up the function and resumes its execution from the "yield" line as if the function had never exited. 38 | 39 | Generator functions can use other functions inside. For instance, it is very common to use the "range" function to iterate over a sequence of numbers: 40 | 41 | ```Python 42 | def squares(n): 43 | for value in range(n): 44 | yield value * value 45 | ``` 46 | 47 | ## Exercises with generators 48 | 49 | 1. Implement a generator called "squares" to yield the square of all numbers from \(a\) to \(b\). Test it with a "for" loop and print each of the yielded values. 50 | 51 | 2. Create a generator to yield all the even numbers from 1 to \(n\). 52 | 53 | 3. Create another generator to yield all the odd numbers from 1 to \(n\). 54 | 55 | 4. Implement a generator that returns all numbers from \(n\) down to 0. 56 | 57 | 5. Create a generator to return the fibonnaci sequence starting from the first element up to \(n\). The first numbers of the sequence are: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... 58 | 59 | 6. Implement a generator that returns all consecutive pairs of numbers from 0 to \(n\), such as (0, 1), (1, 2), (2, 3)... 60 | -------------------------------------------------------------------------------- /chapters/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | In this chapter we will install and run the Python interpreter in your local computer. 4 | 5 | ## Installing on Windows 6 | 7 | 1. Download the latest Python 3 release for Windows on and execute the installer. At the time of writing, this is Python 3.6.4. 8 | 9 | 2. Make sure that the "Install launcher for all users" and "Add Python to PATH" settings are selected and choose "Customize installation". 10 | 11 | ![Windows installation](images/python_windows.jpg){width=62%} 12 | 13 | 3. In the next screen "Optional Features", you can install everything, but it is essential to install "pip" and "pylauncher (for all users)". Pip is the Python package manager that allows you to install several Python packages and libraries. 14 | 15 | 4. In the Advanced Options, make sure that you select "Add Python to environment variables". Also, I suggest that you change the install location to something like C:\\Python36\\ as it will be easier for you to find the Python installation if something goes wrong. 16 | 17 | ![Windows installation](images/python_windows2.jpg){width=62%} 18 | 19 | 5. Finally, allow Python to use more than 260 characters on the file system by selecting "Disable path length limit" and close the installation dialog. 20 | 21 | ![Windows installation](images/python_windows3.jpg){width=62%} 22 | 23 | 6. Now, open the command line (cmd) and execute "python" or "python3". If everything was correctly installed, you should see the Python REPL. The REPL (from Read, Evaluate, Print and Loop) is a environment that you can use to program small snippets of Python code. Run *exit()* to leave the REPL. 24 | 25 | ![Python REPL](images/python_windows4.jpg){width=62%} 26 | 27 | ## Installing on macOS 28 | 29 | You can download the latest macOS binary releases from . Make sure you download the latest Python 3 release (3.6.4 at the time of writing). You can also use Homebrew, a package manager for macOS (). To install the latest Python 3 release with Homebrew, just do "`brew install python3`" on your terminal. Another option is to use the MacPorts package manager () and command "`port install python36`". 30 | 31 | ![Python REPL](images/python_macos.png){width=62%} 32 | 33 | Finally, open the terminal, execute `python3` and you should see the Python REPL as above. Press Ctrl+D or write `exit()` to leave the REPL. 34 | 35 | ## Installing on Linux 36 | 37 | To install Python on Linux, you can download the latest Python 3 source releases from or use your package manager (apt-get, aptitude, synaptic and others) to install it. To make sure you have Python 3 installed on your system, run `python3 --version` in your terminal. 38 | 39 | Finally, open the terminal, execute `python3` and you should see the Python REPL as in the following image. Press Ctrl+D or write `exit()` to leave the REPL. 40 | 41 | ![Python REPL](images/python_linux.png){width=62%} 42 | -------------------------------------------------------------------------------- /chapters/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This book aims to teach the Python programming language using a practical approach. Its method is quite simple: after a short introduction to each topic, the reader is invited to learn more by solving the proposed exercises. 4 | 5 | These exercises have been used extensively in my web development and distributed computing classes at the Superior School of Technology of Setúbal. With these exercises, most students are up to speed with Python in less than a month. In fact, students of the distributed computing course, taught in the second year of the software engineering degree, become familiar with Python’s syntax in two weeks and are able to implement a distributed client-server application with sockets in the third week. 6 | 7 | Please note that this book is a work in progress and, as such, may contain a few spelling errors that may be corrected in the future. However it is made available now as it is so it can be useful to anyone who wants to use it. I sincerely hope you can get something good through it. 8 | 9 | The source of this book is available on github (). I welcome any pull requests to correct misspellings, suggest new exercises or to provide clarification of the current content. 10 | 11 | All the best, 12 | 13 | João Ventura - Adjunct Professor at the Escola Superior de Tecnologia de Setúbal. 14 | -------------------------------------------------------------------------------- /chapters/iterators.md: -------------------------------------------------------------------------------- 1 | # Iterators 2 | 3 | As we saw previously, in Python we use the "for" loop to iterate over the contents of objects: 4 | 5 | ```Python 6 | >>> for value in [0, 1, 2, 3, 4, 5]: 7 | ... print(value*value) 8 | ... 9 | 0 10 | 1 11 | 4 12 | 9 13 | 16 14 | 25 15 | ``` 16 | 17 | Objects that can be used with a "for" loop are called iterators. An iterator is, therefore, an object that follows the iteration protocol. 18 | 19 | The built-in function "iter" can be used to build iterator objects, while the "next" function can be used to gradually iterate over their content: 20 | 21 | ```Python 22 | >>> my_iter = iter([1, 2, 3]) 23 | >>> my_iter 24 | 25 | >>> next(my_iter) 26 | 1 27 | >>> next(my_iter) 28 | 2 29 | >>> next(my_iter) 30 | 3 31 | >>> next(my_iter) 32 | Traceback (most recent call last): 33 | File "", line 1, in 34 | StopIteration 35 | ``` 36 | 37 | If there are no more elements, the iterator raises a "StopIteration" exception. 38 | 39 | ## Iterator classes 40 | 41 | Iterators can be implemented as classes. You just need to implement the "\_\_next\_\_" and "\_\_iter\_\_" methods. Here’s an example of a class that mimics the "range" function, returning all values from "a" to "b": 42 | 43 | ```Python 44 | class MyRange: 45 | 46 | def __init__(self, a, b): 47 | self.a = a 48 | self.b = b 49 | 50 | def __iter__(self): 51 | return self 52 | 53 | def __next__(self): 54 | if self.a < self.b: 55 | value = self.a 56 | self.a += 1 57 | return value 58 | else: 59 | raise StopIteration 60 | ``` 61 | 62 | Basically, on every call to "next" it moves forward the internal variable "a" and returns its value. When it reaches "b", it raises the StopIteration exception. 63 | 64 | ```Python 65 | >>> myrange = MyRange(1, 4) 66 | >>> next(myrange) 67 | 1 68 | >>> next(myrange) 69 | 2 70 | >>> next(myrange) 71 | 3 72 | >>> next(myrange) 73 | Traceback (most recent call last): 74 | File "", line 1, in 75 | StopIteration 76 | ``` 77 | 78 | But most important, you can use the iterator class in a "for" loop: 79 | 80 | ```Python 81 | >>> for value in MyRange(1, 4): 82 | ... print(value) 83 | ... 84 | 1 85 | 2 86 | 3 87 | ``` 88 | 89 | ## Exercises with iterators 90 | 91 | 1. Implement an iterator class to return the square of all numbers from "a" to "b". 92 | 93 | 2. Implement an iterator class to return all the even numbers from 1 to \(n\). 94 | 95 | 3. Implement an iterator class to return all the odd numbers from 1 to \(n\). 96 | 97 | 4. Implement an iterator class to return all numbers from \(n\) down to 0. 98 | 99 | 5. Implement an iterator class to return the fibonnaci sequence from the first element up to \(n\). You can check the definition of the fibonnaci sequence in the function’s chapter. These are the first numbers of the sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... 100 | 101 | 6. Implement an iterator class to return all consecutive pairs of numbers from 0 until \(n\), such as (0, 1), (1, 2), (2, 3)... 102 | -------------------------------------------------------------------------------- /chapters/lists.md: -------------------------------------------------------------------------------- 1 | # Lists 2 | 3 | Python lists are data structures that group sequences of elements. Lists can have elements of several types and you can also mix different types within the same list although all elements are usually of the same datatype. 4 | 5 | Lists are created using square brackets and the elements separated by commas. The elements in a list can be accessed by their positions where 0 is the index of the first element: 6 | 7 | ```Python 8 | >>> l = [1, 2, 3, 4, 5] 9 | >>> l[0] 10 | 1 11 | >>> l[1] 12 | 2 13 | ``` 14 | 15 | Can you access the number 4 in the previous list? 16 | 17 | Sometimes you want just a small portion of a list, a sublist. Sublists can be retrieved using a technique called *slicing*, which consists on defining the start and end indexes: 18 | 19 | ```Python 20 | >>> l = ['a', 'b', 'c', 'd', 'e'] 21 | >>> l[1:3] 22 | ['b', 'c'] 23 | ``` 24 | 25 | Finally, arithmetic with lists is also possible, like adding two lists together or repeating the contents of a list. 26 | 27 | ```Python 28 | >>> [1,2] + [3,4] 29 | [1, 2, 3, 4] 30 | >>> [1,2] * 2 31 | [1, 2, 1, 2] 32 | ``` 33 | 34 | ## Exercises with lists 35 | 36 | Create a list named "l" with the following values ([1, 4, 9, 10, 23]). Using the Python documentation about lists () solve the following exercises: 37 | 38 | 1. Using list slicing get the sublists \[4, 9\] and \[10, 23\]. 39 | 40 | 2. Append the value 90 to the end of the list "l". Check the difference between list concatenation and the "append" method. 41 | 42 | 3. Calculate the average value of all values on the list. You can use the "sum" and "len" functions. 43 | 44 | 4. Remove the sublist [4, 9]. 45 | 46 | ## List comprehensions 47 | 48 | List comprehensions are a concise way to create lists. It consists of square brackets containing an expression followed by the "for" keyword. The result will be a list whose results match the expression. Here’s how to create a list with the squared numbers of another list. 49 | 50 | ```Python 51 | >>> [x*x for x in [0, 1, 2, 3]] 52 | [0, 1, 4, 9] 53 | ``` 54 | 55 | Given its flexibility, list comprehensions generally make use of the "range" function which returns a range of numbers: 56 | 57 | ```Python 58 | >>> [x*x for x in range(4)] 59 | [0, 1, 4, 9] 60 | ``` 61 | 62 | Sometimes you may want to filter the elements by a given condition. The "if" keyword can be used in those cases: 63 | 64 | ```Python 65 | >>> [x for x in range(10) if x % 2 == 0] 66 | [0, 2, 4, 6, 8] 67 | ``` 68 | 69 | The example above returns all even values in range 0..10. More about list comprehensions can be found at . 70 | 71 | ## Exercises with list comprehensions 72 | 73 | 1. Using list comprehensions, create a list with the squares of the first 10 numbers. 74 | 75 | 2. Using list comprehensions, create a list with the cubes of the first 20 numbers. 76 | 77 | 3. Create a list comprehension with all the even numbers from 0 to 20, and another one with all the odd numbers. 78 | 79 | 4. Create a list with the squares of the even numbers from 0 to 20, and sum the list using the "sum" function. The result should be 1140. First create the list using list comprehensions, check the result, then apply the sum to the list comprehension. 80 | 81 | 5. Make a list comprehension that returns a list with the squares of all even numbers from 0 to 20, but ignore those numbers that are divisible by 3. In other words, each number should be divisible by 2 and not divisible by 3. Search for the "and" keyword in the Python documentation. The resulting list is \[4, 16, 64, 100, 196, 256\]. 82 | -------------------------------------------------------------------------------- /chapters/loops.md: -------------------------------------------------------------------------------- 1 | # Iteration and loops 2 | 3 | In this chapter we are going to explore the topics of iteration and loops. Loops are used in computer programming to automate repetitive tasks. 4 | 5 | In Python the most common form of iteration is the "for" loop. The "for" loop allows you to iterate over all items of a list such that you can do whatever you want with each item. For instance, let’s create a list and print the square value of each element. 6 | 7 | ```Python 8 | >>> for value in [0, 1, 2, 3, 4, 5]: 9 | ... print(value * value) 10 | ... 11 | 0 12 | 1 13 | 4 14 | 9 15 | 16 16 | 25 17 | ``` 18 | 19 | It’s quite easy but very powerful\! The "for" loop is the basis of many things in programming. For instance, you already know about the "sum(list)" function which sums all the elements of a list, but here’s an example using the "for" loop: 20 | 21 | ```Python 22 | >>> mylist = [1,5,7] 23 | >>> sum = 0 24 | >>> for value in mylist: 25 | ... sum = sum + value 26 | ... 27 | >>> print(sum) 28 | 13 29 | ``` 30 | 31 | Basically, you create the variable "sum" and keep adding each value as it comes from the list. 32 | 33 | Sometimes, instead of the values of a list, you may need to work with the indexes themselves, i.e., not with the values, but the positions where they are in the list. Here’s an example that iterates over a list and returns the indexes and the values for each index: 34 | 35 | ```Python 36 | >>> mylist = [1,5,7] 37 | >>> for i in range(len(mylist)): 38 | ... print("Index:", i, "Value:", mylist[i]) 39 | ... 40 | Index: 0 Value: 1 41 | Index: 1 Value: 5 42 | Index: 2 Value: 7 43 | ``` 44 | 45 | You can see that we are not iterating over the list itself but iterating over the "range" of the length of the list. The range function returns a special list: 46 | 47 | ```Python 48 | >>> list(range(3)) 49 | [0, 1, 2] 50 | ``` 51 | 52 | So, when you use "range" you are not iterating over "mylist" but over a list with some numbers that you’ll use as indexes to access individual values on "mylist". More about the range function in the Python docs at . 53 | 54 | Sometimes you may need both things (indexes and values), and you can use the "enumerate" function: 55 | 56 | ```Python 57 | >>> mylist = [1,5,7] 58 | >>> for i, value in enumerate(mylist): 59 | ... print("Index:", i, "Value:", value) 60 | ... 61 | Index: 0 Value: 1 62 | Index: 1 Value: 5 63 | Index: 2 Value: 7 64 | ``` 65 | 66 | Remember that the first value on a Python list is always at index 0. 67 | 68 | Finally, we also have the "while" statement that allows us to repeat a sequence of instructions while a specified condition is true. For instance, the following example starts "n" at 10 and **while "n" is greater than 0**, it keeps subtracting 1 from "n". When "n" reaches 0, the condition "n \> 0" is false, and the loop ends: 69 | 70 | ```Python 71 | >>> n = 10 72 | >>> while n > 0: 73 | ... print(n) 74 | ... n = n-1 75 | ... 76 | 10 77 | 9 78 | 8 79 | 7 80 | 6 81 | 5 82 | 4 83 | 3 84 | 2 85 | 1 86 | ``` 87 | 88 | Notice that it never prints 0... 89 | 90 | ## Exercises with the for loop 91 | 92 | For this section you may want to consult the Python docs at . 93 | 94 | 1. Create a function "add" that receives a list as parameter and returns the sum of all elements in the list. Use the "for" loop to iterate over the elements of the list. 95 | 96 | 2. Create a function that receives a list as parameter and returns the maximum value in the list. As you iterate over the list you may want to keep the maximum value found so far in order to keep comparing it with the next elements of the list. 97 | 98 | 3. Modify the previous function such that it returns a list with the first element being the maximum value and the second being the index of the maximum value in the list. Besides keeping the maximum value found so far, you also need to keep the position where it occurred. 99 | 100 | 4. Implement a function that returns the reverse of a list received as parameter. You may create an empty list and keep adding the values in reversed order as they come from the original list. Check what you can do with lists at . 101 | 102 | 5. Make the function "is\_sorted" that receives a list as parameter and returns True if the list is sorted in ascending order. For instance \[1, 2, 2, 3\] is ordered while \[1, 2, 3, 2\] is not. Suggestion: you have to compare a number in the list with the next one, so you can use indexes or you need to keep the previous number in a variable as you iterate over the list. 103 | 104 | 6. Implement the function "is\_sorted\_dec" which is similar to the previous one but all items must be sorted by decreasing order. 105 | 106 | 7. Implement the "has\_duplicates" function which verifies if a list has duplicate values. You may have to use two "for" loops, where for each value you have to check for duplicates on the rest of the list. 107 | 108 | ## Exercises with the while statement 109 | 110 | 1. Implement a function that receives a number as parameter and prints, in decreasing order, which numbers are even and which are odd, until it reaches 0. 111 | 112 | >>> even_odd(10) 113 | Even number: 10 114 | Odd number: 9 115 | Even number: 8 116 | Odd number: 7 117 | Even number: 6 118 | Odd number: 5 119 | Even number: 4 120 | Odd number: 3 121 | Even number: 2 122 | Odd number: 1 123 | -------------------------------------------------------------------------------- /diagrams/consumers_pipeline.txt: -------------------------------------------------------------------------------- 1 | +-------------+ 2 | send() | | 3 | +---->+ CONSUMER #1 | 4 | | | | 5 | +----------+ +----------+ | +-------------+ 6 | | | send() | +--+ 7 | | SOURCE +------->+ PRODUCER | 8 | | | | +--+ 9 | +----------+ +----------+ | +-------------+ 10 | | | | 11 | +---->+ CONSUMER #2 | 12 | send() | | 13 | +-------------+ 14 | -------------------------------------------------------------------------------- /diagrams/coroutine_pipeline.txt: -------------------------------------------------------------------------------- 1 | +----------+ +-----------+ +-----------+ 2 | | | send() | | send() | | 3 | | SOURCE +------->+ COROUTINE +------->+ COROUTINE | 4 | | | | | | | 5 | +----------+ +-----------+ +-----------+ 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /diagrams/instructions.txt: -------------------------------------------------------------------------------- 1 | 1. Draw diagrams with http://asciiflow.com/ 2 | 2. Convert to png with http://ditaa.sourceforge.net/ 3 | 3. java -jar ditaa0_9.jar XXX.txt --scale 2 -------------------------------------------------------------------------------- /images/consumers_pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoventura/full-speed-python/35a854208b2ed43f00e025585c8c4d87322ccda0/images/consumers_pipeline.png -------------------------------------------------------------------------------- /images/coroutine_pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoventura/full-speed-python/35a854208b2ed43f00e025585c8c4d87322ccda0/images/coroutine_pipeline.png -------------------------------------------------------------------------------- /images/pip_windows.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoventura/full-speed-python/35a854208b2ed43f00e025585c8c4d87322ccda0/images/pip_windows.jpg -------------------------------------------------------------------------------- /images/python_linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoventura/full-speed-python/35a854208b2ed43f00e025585c8c4d87322ccda0/images/python_linux.png -------------------------------------------------------------------------------- /images/python_macos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoventura/full-speed-python/35a854208b2ed43f00e025585c8c4d87322ccda0/images/python_macos.png -------------------------------------------------------------------------------- /images/python_windows.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoventura/full-speed-python/35a854208b2ed43f00e025585c8c4d87322ccda0/images/python_windows.jpg -------------------------------------------------------------------------------- /images/python_windows2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoventura/full-speed-python/35a854208b2ed43f00e025585c8c4d87322ccda0/images/python_windows2.jpg -------------------------------------------------------------------------------- /images/python_windows3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoventura/full-speed-python/35a854208b2ed43f00e025585c8c4d87322ccda0/images/python_windows3.jpg -------------------------------------------------------------------------------- /images/python_windows4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoventura/full-speed-python/35a854208b2ed43f00e025585c8c4d87322ccda0/images/python_windows4.jpg -------------------------------------------------------------------------------- /metadata.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | title: Full Speed Python 3 | subtitle: v0.4.3 4 | author: João Ventura 5 | lang: en-US 6 | 7 | # Variables for Latex 8 | documentclass: book 9 | classoption: oneside 10 | fontsize: 12pt 11 | toc: true 12 | --- 13 | -------------------------------------------------------------------------------- /tex/preamble.tex: -------------------------------------------------------------------------------- 1 | % Paper and margins 2 | \usepackage[a4paper, margin=1in]{geometry} 3 | 4 | % Fonts 5 | \usepackage[]{opensans} 6 | \usepackage[T1]{fontenc} 7 | \usepackage[utf8]{inputenc} 8 | 9 | % Images 10 | \usepackage{graphicx} 11 | \usepackage{float} 12 | 13 | % All images should be where they are defined 14 | \makeatletter 15 | \def\fps@figure{H} 16 | \makeatother 17 | 18 | % Headers and footers 19 | \pagestyle{plain} 20 | --------------------------------------------------------------------------------