mersenneforum.org

mersenneforum.org (https://www.mersenneforum.org/index.php)
-   Dylan14 (https://www.mersenneforum.org/forumdisplay.php?f=164)
-   -   A Guide for Python (https://www.mersenneforum.org/showthread.php?t=24905)

Dylan14 2019-11-03 04:27

A Guide for Python
 
This thread is intended to be a guide to program in Python, starting (hopefully) from the beginning. It is intended for those using the Colab/Kaggle interface, but it can be useful for those using a standalone Python interpreter.
There is a separate thread for comments ([URL]https://mersenneforum.org/showthread.php?t=24906[/URL]). Post comments on this guide in that thread.

Table of contents:
1. Table of contents (this post)
2. Motivation for this guide [URL]https://mersenneforum.org/showpost.php?p=529520&postcount=2[/URL]
3. How to get/use Python [URL]https://mersenneforum.org/showpost.php?p=529521&postcount=3[/URL]
4. Basic syntax [URL]https://mersenneforum.org/showpost.php?p=529594&postcount=4[/URL]
5. Comment lines [URL]https://mersenneforum.org/showpost.php?p=529595&postcount=5[/URL]
6. Some basic constructs: strings, integers, floats, complexes, bools [URL]https://mersenneforum.org/showpost.php?p=529596&postcount=6[/URL]
7. The "print" command and your first program [URL]https://mersenneforum.org/showpost.php?p=530160&postcount=7[/URL]
8. String concatenation and the "input" command [URL]https://mersenneforum.org/showpost.php?p=530408&postcount=8[/URL]
9. The "format" command [URL]https://mersenneforum.org/showpost.php?p=530409&postcount=9[/URL]
10. If/else, part 1: the if statement and the else statement [URL]https://mersenneforum.org/showpost.php?p=530942&postcount=10[/URL]
11. If/else, part 2: the elif statement [URL]https://mersenneforum.org/showpost.php?p=531356&postcount=11[/URL]
12. Functions [URL]https://mersenneforum.org/showpost.php?p=532229&postcount=12[/URL]
13. A slight digression: modules [URL]https://mersenneforum.org/showpost.php?p=533339&postcount=13[/URL]
14. For loops, part 1: introduction to for loops [URL]https://mersenneforum.org/showpost.php?p=533522&postcount=14[/URL]
15. For loops, part 2: break and continue [URL]https://mersenneforum.org/showpost.php?p=534642&postcount=15[/URL]
16. While loops [URL]https://mersenneforum.org/showpost.php?p=534733&postcount=16[/URL]
17. Putting all the loops together [URL]https://mersenneforum.org/showpost.php?p=534920&postcount=17[/URL]
18. More on strings - indexing, repeating, slicing [URL]https://www.mersenneforum.org/showpost.php?p=551057&postcount=18[/URL]
19. Miscellaneous string operations [URL]https://www.mersenneforum.org/showpost.php?p=551058&postcount=19[/URL]
20. Introduction to lists
21. Operations on lists - indexing, slicing, concatentation, etc.
22. The math module
23. The cmath module
24. etc tbd

Dylan14 2019-11-03 04:27

Motivation for the Guide
 
So you might be wondering why I am writing this guide here. This is a valid point. In fact, I can see multiple points of contention:


1. There is, like, a thousand other tutorials out there on the Internet that do the same thing (in fact, the Python devs themselves have a tutorial, see [URL]https://docs.python.org/3/tutorial/[/URL].) Why would this be any different?
2. Why Python, out of all languages? It's not as efficient as, say C, or Fortran, or (insert any other compiled language).
3. Why not just stick with the codes that already exist?



All of these are valid points. To justify this guide, I can reason as follows:


1. With regards to the availability of tutorials on the Internet and in books, it is easy to find information on the language. But say you want something that's more obscure, like for certain packages that you can find on PyPi. Then chances are, you won't find any tutorials on this, and you are left to study the source and you have no idea what's going on. Also, some tutorials are arranged differently than others. While most tutorials will start with the usual stuff like syntax, strings, variables, etc., there is a limit to where the guides go to, and then you have to switch to another one, or rely on the Python documentation which may be cryptic at some points. And some things that are covered may not be needed. For example, certain Linux programs can be run on Colab/Kaggle without calling Python.


2. There are several reasons why I chose to use Python for this guide.
a) The code is easy to read, especially with properly commented code.
b) The code is well defined and has specific syntax.
c) Python can be extended easily by importing modules. Want to plot stuff? Use matplotlib! Need to deal with large arrays of numbers? Use numpy! Want to simulate a particle collider, use vegas! etc. etc.
d) Code will work as long as you have an interpreter, which exists for Windows, Mac and Linux.
e) Python can be linked to databases like MySql.


3. The easy answer (which is more of a question in its self): What if say the code doesn't exist that solves your problem?
A more valid answer: let's consider the OEIS database. There are a lot of sequences that don't have code. Some are due to the fact that the function is not computable, or the next term in the sequence is not known, so creating code for this would be impossible or impractical (for example, [URL="https://oeis.org/A028444"]the busy beaver sequence[/URL]). Others are trivial to make code for, but they have no code in a language (for example, [OEIS]210009[/OEIS] - a formula exists which is a recursion relation which can be coded up). And this is just for math stuff! What about more practical things?


4. Learning a new language might help your programming in other languages.


5. You might have the next big idea that assists people or assists the search for primes, or factors. Being able to code will allow others to benefit. (Hell, you might be able to improve prime95/mprime*).


Thus, this guide is created to provide a detailed study of Python and other useful modules.


(*) This might be hard. George Woltman et al. have done a great job in optimizing the program and implementing things that make primality checking fast and reliable.

Dylan14 2019-11-03 04:29

How to get/use Python
 
Of course, before we can actually go about and learn how to use Python, we need to first acquire the Python interpreter/environment. There are several ways to do this:


1. Download Python from the official website, [URL]https://www.python.org/downloads/[/URL].
This is the easiest method to get up and running with Python on a standalone interpreter. It will give you the following by default (at least on a Windows install):
* documentation files
* pip (a useful tool to install additional packages)
* tcl/tk and IDLE (a dev environment)
* the python test suite
* the py launcher (makes it easier to run the interpreter)
There are multiple versions available; it is recommended to run the latest version (which at the time of post is 3.8.1)(*), as I will be using Python 3 here for this guide (**).


2. Use a pre-built distribution of Python, which includes a bunch of packages right off the bat. There are several of these available, although not all of them are compatible with every OS choice. For this I recommend the Anaconda distribution (available [URL="https://www.anaconda.com/distribution/"]here[/URL], which installs a bunch of packages which will be useful later on (like numpy, matplotlib, etc.) and has pip which allows one to install more packages. Of course, you may pick a different one, see, for example, [URL]https://wiki.python.org/moin/PythonDistributions[/URL].


3. (Linux only) In several distros of Linux, Python is automatically installed. If for some reason, it is not, you can use the package manager included on your distro. To do this on Ubuntu, do the following:
* first run sudo apt-get update to update the repositories (inserting your root password if needed)

* then run sudo apt-get install python3 python3-pip and answer y when prompted. This will install the python interpreter, the pip package manager and any dependencies.
If you have a different distribution of Linux, then you may have to change apt-get to the appropriate name and parameters for your package manager (pacman, yum, etc.).


4. Online editors: there are several of them out there. The only ones that I have major experience with here are the ones on Google Colaboratory and Kaggle. Both of these use notebook style interfaces which are not too dissimilar to the Jupyter notebook that is used in the Anaconda distribution. For the Colab, you will need a Google account to proceed, and for Kaggle you will need to make an account. Once done, you can create notebooks. More information on these can be found in the following [URL="https://mersenneforum.org/showthread.php?t=24646"]two[/URL] [URL="https://mersenneforum.org/showthread.php?t=24839"]threads.[/URL]


Note: if you running the code locally, it will be useful to have a text editor, like emacs, gedit, or notepad++.


Running the interpreter:


Once you have the interpreter installed on your machine, then you can call the interpreter by invoking the following


[CODE]python[/CODE]or
[CODE]python3[/CODE]This assumes that python is in your path, if not, you will need to type the full path in to the interpreter, or add the path to the directory where python lives to your environment variables.
The end result should look like this:
[CODE]C:\Users\Dylan>"C:\Users\Dylan\Anaconda\envs\Python 3\python.exe"
Python 3.7.4 (default, Aug 9 2019, 18:34:13) [MSC v.1915 64 bit (AMD64)] :: Anaconda, Inc. on win32

Warning:
This Python interpreter is in a conda environment, but the environment has
not been activated. Libraries may fail to load. To activate this environment
please see https://conda.io/activation

Type "help", "copyright", "credits" or "license" for more information.
>>>[/CODE](ignore the warning here, this is a thing from conda).
If you are using Colab, once you login you will have a window which will show the available notebooks. Click on "New Python 3 notebook" and then a new notebook will open.
If you are using Kaggle, once you login, go to "Notebooks", then click on "New Notebook". Leave the settings as is, and then click on "Create". A new kernel will be created with a cell filled with an example piece of code, and an empty cell.
Once ready, we can move on to the next bit.



(*) The download page has pretty much every single minor version and bugfix version of Python, and there are even tarballs for version 1 of Python.
(**) Python 1 is very much out of date (1.6 was released in 2000). Python 2 reached end of life on January 1, 2020. It is of course still available in some Linux repos (for example, Debian 10 (Buster) still ships with it, but Ubuntu 20.04 LTS (Focal) will not have Python 2 in the main repository).

Dylan14 2019-11-04 00:36

Basic Syntax
 
In order to code, you must understand two things:
1. The functions that make up the language (otherwise you aren't going to do anything).
2. The syntax used in the language. This is arguably more important than knowing the functions. You may have a nice program that spans 10000 lines, but if you have simply one syntax error, the compiler/interpreter will complain with a syntax error, and you will be forced to scan through your entire code to find the error.

Now, each function has its own syntax depending on what it takes as arguments. For a simple example, let's take a look at SeedSequence from the random module in numpy:

[CODE][I]class [/I]numpy.random.SeedSequence([I]entropy=None[/I], [I]*[/I], [I]spawn_key=()[/I], [I]pool_size=4[/I])[/CODE]This function has 3 arguments, all of them optional, since each of them have a default value. The default value for each of these is defined by using the equals sign and then after the equals sign a value is given. Each of these arguments also takes a certain type of input. For example, the "entropy" argument may take the value of "None", an integer, or a sequence of integers.
We'll get to functions later on in the guide. For now, we will deal with the basic syntax of Python. Firstly, we can't just enter random characters into a prompt(*). Typing


[CODE]x[/CODE]will yield an error:

[CODE]NameError Traceback (most recent call last)

<ipython-input-2-6fcf9dfbd479> in <module>
----> 1 x

NameError: name 'x' is not defined[/CODE] In fact, before you can reference a "name", you need to define it first. So, say we want to initialize x to 0 (as for a counter). We can do this by typing the following:

[CODE]x = 0[/CODE]Now, x is defined. If we type x now in a new cell, we get the following

[CODE]0
[/CODE]The next thing that we need to be wary of is the types of our variables(**). It will not end well if you try to add, say, an integer and a string. Try

[CODE]x + "a"[/CODE]Here, if you defined x = 0 as above, then x is an integer and "a" is a string. Clearly addition or concatenation doesn't work between these two types, and we get a TypeError:

[CODE]TypeError Traceback (most recent call last)
<ipython-input-5-3fb36790c1e0> in <module>
----> 1 x + "a"
TypeError: unsupported operand type(s) for +: 'int' and 'str' [/CODE] But it clearly works if we have an integer. Typing this

[CODE]x+1[/CODE]should yield 1, and no errors.
Now another thing to note is that in Python, we use indents to denote control flow blocks, and we do not need to end lines with the semicolon character. This is in stark comparison to C, where you use curly braces to denote control flow blocks, and you use semicolons. Here's a symbolic example:
Python:
[CODE]while(x <= 10):
dosomething()
dosomethingelse()
[/CODE](***)

C (****):
[CODE]while(x <= 10)
{
dosomething();
dosomethingelse();
}[/CODE]With this style of demarcation, you must be careful with your indents. Editors may have different styles. For example, on Colab, it uses 2 spaces for an indent, whereas on Kaggle and notepad++ it uses 4 spaces. On others a tab is used. I will use 4 spaces for the code examples.
More specific syntax will be introduced when we need it.

(*) Well, you can, but first you need to make the line a comment line first. See the section on Comments for more information.
(**) Some information on some common types in plain Python are located in the post labeled "Basic Constructs".
(***) Don't actually try to run this: this is only here as an example of the indent style.
(****) This follows the Allman brace placement. There are several other ones, but this is outside the scope of this guide.

Dylan14 2019-11-04 00:37

Comments
 
Perhaps the most useful thing of good code is well commented code. After all, without them, we would just have to rely on reading the source code and hope that we understand what is going on in the code. Of course, the comments should be about the code (or, at the very least, clean, without obscenities. I.e., don't be like Ponytail in [XKCD]1790[/XKCD]!)
So what do I mean by well commented code? I say that code is "well commented" if it satisfies the following:
1. Each piece of a script or program is commented.
2. The comments are relevant and explain clearly what is going on at that point. Comments need not be sentences or regular statements (sometimes a question is best).
3. Comments are marked in the right place within the code (meaning, if you have a function withing the code that takes a function and then plots it, you would not mark a comment saying to plot the function when you are evaluating the function at multiple points).
4. (Optional) If a piece of code goes through multiple iterations, it may be worth commenting what versions and changes have gone on over time.
The last point is optional since a) version control via svn or git keeps track of changes in the code, and b) some authors may include a file called changes.txt which says what has changed.
Now how does one do comments in Python. This is very simple. For a single line comment, one can preface the line with the following character:


[CODE]#[/CODE]Once this character is placed in a line, the rest of the line is not evaluated when the interpreter is run. As an example, run a script with the following:


[CODE]#This comment comes from mersenneforum's Python guide.[/CODE](nothing should come out and you should return to the prompt).
The # character can also come anywhere in the line and everything after that is treated as a comment. Such a comment is an inline comment. An example can be found in my mlucas compilation script, where we check to see if the error log is empty before we go and and link:
[CODE]if os.stat("erroravx512.log").st_size == 0: #grep came up empty[/CODE]Now what about multiline comments?
Unlike, say, Java, you can't just do something like


[CODE]/* Some comments need
more than one line,
like this one */[/CODE]Or like this:


[CODE]#Some comments need
more than one line,
like this one[/CODE](the second code example will ignore the first line, but the code will error out with a syntax error when it hits the second line). So how do we do a multi-line comment? We have two options:
1. For each line, we preface the line with a # character.
2. Encase the comment in triple quotes.


Applying this to the last code block, the following are equivalent(*):
[CODE]#Some comments need
#more than one line,
#like this one[/CODE][CODE]"""
Some comments need
more than one line,
like this one
"""[/CODE](*) Care has to be taken with the triple quotes. In actuality this is a string that isn't referenced by anything, so it doesn't do anything in the program. Also, if you use this construct inside a function, then the object becomes a docstring (documentation string) associated with that function. If in doubt, just use the # character!

Dylan14 2019-11-04 00:37

Basic Constructs: strings, integers, floats, complexes, bools
 
Okay, we've covered how to get python, we've covered how to be wary of our syntax, and we've learned how to comment and (hopefully) do it properly. We should be ready to go, right? Not so fast. In codes, unless we're doing something very simple like printing "Hello World!" to the screen (*), we will generally have functions that take some input, do stuff (**) with that input, and then return something back to the user, either directly or into another function.
Now in something like C or C++, functions themselves have type, like int, void, etc. etc. This is not the case with Python. Here, the variables themselves are typed, and the functions are not. This is important!
Okay, but what types are there to use? In standard Python 3, we have many different types that we can use. These include:
* bool (a boolean, which can take the value 0 or 1, or alternatively "True" or "False"
* int (an integer)
* float (a floating point number)
* complex (a complex number of the form a + bj) (***)
* containers and iterators (iterate over objects within the container)
* lists (mutable sequence, used to store collections of similar objects)
* tuples (immutable sequences containing heterogeneous data, or for use in sets/dictionaries)
* ranges (used for "for" loops)
* strings (for text data)
* and more (see [URL]https://docs.python.org/3.8/library/stdtypes.html[/URL] for all built in types)

Some modules will introduce other types. A notable example is the array class in numpy (which can be thought of as a matrix). Here, we will focus on 5 classes which appear very often in python: strings, integers, floats, complexes and bools.

Bools:
A bool is short for a boolean. This is a type which has two values: either 0 (denoting "off" or "false") or 1 (denoting "on" or "true"). The values themselves are not really helpful in themselves, but they are useful when setting conditions for while loops and for if/else statements, which we will cover later. The Boolean operators are "and", "or", and "not". To understand these, one should know the truth tables of these expressions (****). Let a and b be logical statements. Then the operators will yield

*and - evaluates false if one of a or b are false.
*or - evaluates false if both a and b are false.
*not - evaluates true if the statement is false, else it's false.
Booleans also come about when using comparisons, of which there are 8 of these defined in Python - < (less than), <= (less than or equal), > (greater than), >= (greater than), == (equal), != (not equal), is (object identity) and is not (negated object identity).
Some of these operators (such as <, <=, > and >=) are only defined in certain cases. For example, if one of the arguments is a complex number, then a TypeError will be raised.

Int:

Int is short for integer. Integers are defined as you would expect in mathematics. You can have integers as large as you would like in Python 3, as long as you have enough memory. For example, here is M1693:

[CODE][COLOR=#d4d4d4][FONT=monospace][COLOR=Black](2**1693)-1[/COLOR]
[/FONT][/COLOR][/CODE]yields
[CODE]440334444803013926723870430995863483703366909461783710471893932957885075695846526218526403061701134167211016236435527577005050015233222965976326940896095207044707758848508612460210362291110289652838518022120032380292451462329609095153231156707074655775395637629132002575140637348625684412427398984395674716936018562692034858963987306844991080918202832393268803551844553169715869473510245310131838410602687073367986808845044441458533294015993729099271507428272873558378015567915849627392090773401429909849505791[/CODE]The usual operators can be used for integers, such as +, -, *, /, % (modulus), abs(x) (absolute value), and ^ (exponentiation, which can be implemented by using ** or pow(x, y)). There is also //, which is the floored quotient function (or integer division), which gives the whole integer value of the division, rounded down. Also, there is the divmod function, which gives the pair x // y, x % y.

Float:
Floats are floating point numbers. This type is needed because often times, it is not necessary to have infinite precision (or even possible) to have infinite precision, due to memory constraints. Depending on what scale we are working with (nanoscale or planetary scale), we need to have accuracy at different scales. To deal with this, floating point numbers are needed. Floating point numbers are defined by the IEEE 754 standard (*****). These have the same operations available as integers.

Complexes:
Complexes cover complex numbers. A complex number can be written in Python via the following:

[CODE]complex(real, (imag))[/CODE]For example, the number 3 + 4i can be written by typing:

[CODE]complex(3, 4)[/CODE]or

[CODE]3+4j[/CODE]You can't use the % operator or the divmod operator for complexes. However, you also get a new operator in the c.conjugate() function which returns the complex conjugate.

Strings:

The last class we will cover are strings. Strings are used to convey text information. These can be parsed and stripped and otherwise manipulated (we will go over this later when we deal with list comprehension). A string is denoted by either single quotes ' ', double quotes " ", or triple quotes in either version (""" """ or ''' '''). The triple quotes can be used to do multiline strings.
Strings can contain any character you'd like, but some characters need to be escaped. To escape a character, you use a \ (backslash). This is used, for example, if you need to add a tab or a new line character. You can also use \ to prefix special characters like the quotes, or for characters defined by their ASCII or Unicode values. For example, typing

[CODE]print("\u03b3")[/CODE]will yield

[CODE]γ[/CODE]the symbol for lowercase gamma.

All of the escape characters can be found on this site: [URL]https://www.quackit.com/python/reference/python_3_escape_sequences.cfm[/URL].

(*) The "Hello World" program is usually the first program that people learning to program will write up. Granted, it's not really that useful on its own (you could just type echo "hello world" in a command prompt and do the same thing without invoking python). However, printing stuff to screen can be useful when you go debug a program. I will cover this in the next section.
(**) I'm pretty sure "stuff" is the technical term here.
(***) This is the notation that Python uses for complexes, which is similar to what an electrical engineer would use. Mathematicians should interpret this a + bi. Still, they mean the same thing:

[TEX]i = j = \sqrt {-1}[/TEX]

(****) A truth table is a construct in logic used to determine the validity of a logical statement. More information can be found here: [URL]https://en.wikipedia.org/wiki/Truth_table[/URL].
(*****) See [URL]https://www.geeksforgeeks.org/ieee-standard-754-floating-point-numbers/[/URL] for an overview.

Dylan14 2019-11-10 02:48

The Print Command and your first program
 
Now in the previous post in this guide I mentioned the "Hello World" program being the first program that aspiring programmers type out in the language of their choice. With our background that we have developed so far, we are now ready to get to this concept of printing messages to the screen, which is ultimately what the "Hello World" program demonstrates.

The "print" command:

Print is a simple built-in function that takes in a string and then prints it to the screen. This is invoked by typing the following:

[CODE]print(string)[/CODE]This is the simplest invocation of the print command. Note here that the "string" can be a chain of strings strung together, using concatenation. We can also format the string using the format command. These will be the subjects of the next two sections of the guide.
Actually, print has some keyword arguments, although these are hardly used. The full syntax for the print command is

[CODE]print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)[/CODE]Here's what all the arguments mean:
* *objects - specifies what objects should be printed. The * indicates that we can link multiple objects. Objects to be printed have to be separated with commas.
* sep = ' ' - objects are to separated with this string. By default, it is a space.
* end = '\n' - The object to be printed at the end of the objects. By default, it is a new line (note the escape character).
*file = sys.stdout - Specifies where the output will be sent to. The output location must be an object with the write(string) method. By default, it is sent to sysout, i.e., it gets output to the screen.
*flush - Takes either the value of True or False. If True, the stream is forcibly flushed. If False, it is not. The default is False.

Your first program:

Now, we have a function that we can play around with. Therefore, we can create programs with it. The simplest one that we can write is the "Hello World" program, which I have mentioned a few times already. To create this, open up a Python shell/notebook and type the following:

[CODE]print("Hello world!")[/CODE]This will yield the following:

[CODE]Hello world![/CODE]Congrats! You have now written your first program in Python!

Ok, celebrations aside, this is great, but it is limited to whatever we put in the string. To improve this, we can use the input() (*) command, which will ask for user input. Try this code:

[CODE]string = input("Type something: ")
print(string)[/CODE]This yields, after user input:

[CODE]Type something: Welcome to mersenneforum's python guide
Welcome to mersenneforum's python guide[/CODE] Now, we can type whatever we'd like to print. Which is always nice.
In the future we can use format() and string concatenation to make more intricate things to print.

(*) The input command will be covered in more detail later.

Dylan14 2019-11-12 23:07

Concatenation of strings and the "input" command
 
In the previous section, we dealt with the print command and we also took our first serious look at strings. However, we kept it very simple, and we considered only one string at a time. Now, what if we want to have multiple strings? This is very simple: we can define two variables as strings. We can also print said strings:

[CODE]string1 = "This is a string"
string2 = "I like mersenneforum"
print(string1)
print(string2)[/CODE]This yields:

[CODE]This is a string
I like mersenneforum[/CODE]Now, suppose we want to connect the strings together, so that we have one string that contains both string1 and string2. In order to do this, we need to use string concatenation. Luckily, we can do easily in Python. If we use the plus sign between two string objects, we can "concatenate" them together.
Going back to the previous strings that we defined, we could concatenate as follows:
[CODE]string1 = "This is a string"
string2 = "I like mersenneforum"
string3 = string1 + string2
print(string3)

[/CODE]This gives the following:
[CODE]This is a stringI like mersenneforum[/CODE]This leads to a thing about concatenation: it just sticks the strings together into one, without putting any white space between the two.(*)
Now, what if we have more than two strings that we want to concatenate? Easy! Just put a plus sign between each string you want to string together, like so:

[CODE]print("This is a string " + "and " + "I like mersenneforum")[/CODE]which yields

[CODE]This is a string and I like mersenneforum[/CODE]Note that I only used three strings in this example. You can expand this to N strings, where N is any positive number greater than 2. Just make sure to put a plus sign next to each pair of strings.(**)

The "input" command:

In the previous section, I used the input() command to get Python to print whatever we wanted to type. It would be wrong to just ignore what it does before we get too deep into the guide, so we will cover it here.
The input function is a simple function, which may take either 0 or 1 arguments. It basically interrupts the interpreter, requests user input, and then when the user presses Enter on the keyboard, the program will continue. The only argument that can be placed in the function is a string, which will be a prompt which will be printed when the interpreter reaches that point in the program.
The input function will encounter an error if an end of file character is received (***).
Example of input() without a prompt:

[CODE]print(input())[/CODE]This will print out whatever you type in.

Example of input() with a prompt:

[CODE]age = input('Enter your age: ')
print("You are " + str(age) + " years old")[/CODE]this prints out the user's age:

[CODE]Enter your age: 23
You are 23 years old[/CODE]The EOFError (on Google Colab, after pressing Ctrl+D in input())(****):

[CODE]EOFError Traceback (most recent call last) [COLOR=Black][URL="https://localhost:8080/#"]<ipython-input-6-6610b0876cd9>[/URL] in <module>() [/COLOR]
[COLOR=Black]----> 1 print(input())[/COLOR][COLOR=Black]
[/COLOR][COLOR=Black] [URL="https://localhost:8080/#"]/usr/local/lib/python3.6/dist-packages/ipykernel/kernelbase.py[/URL] in _input_request(self, prompt, ident, parent, password) [/COLOR]
[COLOR=Black][B]743[/B] if value == '\x04': [/COLOR]
[COLOR=Black][B] 744[/B] # EOF [/COLOR]
[COLOR=Black]-->[/COLOR][COLOR=Black]745 raise EOFError [/COLOR]
[COLOR=Black][B]746[/B] return value [/COLOR]
[COLOR=Black][B]747[/B]
[/COLOR]
[COLOR=Black]EOFError: [/COLOR]
[/CODE](*) You can kind of think of string concatenation as "gluing" strings together.
(**) Note that they must be strings, otherwise you will get a TypeError (see Basic Syntax). You can bypass this by using the str() command, which will try to change the type of the thing inside the parentheses to a string. I'll explain this in more detail later.
(***) On Unix/Linux systems, pressing Ctrl+D will send the EOF signal, whereas on a Windows machine, pressing Ctrl+Z+Enter will do this.
(****) In the error, we have the string '\x04'. So, hex character 04 is the EOF character (recall \xhh inside a string means to escape the character with hex value hh. In ASCII, hex 04 is not defined to anything, and hex 26 is reserved for the DOS end of file character. In general this is not really important since in most cases you will have non empty input.

Dylan14 2019-11-12 23:07

The format command
 
Do you know that in a lot of programs one can change how things are formatted? For example, many word processors (including the WYSIWYG editor that I am using to type this part of the tutorial) have many options available to change how text looks, such as font size, color and alignment. In programming, this isn't what we are referring to, but rather how things are presented to the end user. This can be seen in various programs that are used on Mersenneforum and elsewhere.

A teaser: a look at mfaktc's PrintFormat option(*):

Mfaktc has several options available to influence how it operates. Most of the options affect the usage of the GPU, but there is an option in the ini file to adjust what it prints on the screen when it completes a class. This option is called "PrintFormat". I won't go through the full options (refer to the threads linked, or in your instance of mfaktc), but we'll look at a few of the options.
First, we'll look at %t, which is the option for the time elapsed per class. There are four ways it can be printed, depending on the number that needs to be displayed: "%6.0f" (no decimal places), "%6.1f" (1 decimal place), "%6.2f" (2 decimal places), or "%6.3f" (3 decimal places). These will display up to 6 digits.
As another example, we can look at %M, the exponent. This is a number which can be up to 10 decimal digits (as the exponent limit of mfaktx is 2^32-1). This is expressed in the format string, "%-10u".
The rest should make more sense after we go through how Python handles string formatting.

Python's format command:

The format command is part of the core language, in the string.py file. The syntax is the following:

[code]{}.format(string_to_be_formatted, /, args, kargs)[/code]As a simple example, we will consider a substitution of text in the format:

[CODE]print("mersenneforum likes the following program: {}".format("Prime95"))[/CODE]This yields the following string:

[code]mersenneforum likes the following program: Prime95[/code] As we can see, python inserted the text Prime95 in the space marked by the curly brackets. Now, of course, we can specify multiple sets of curly brackets, and when we do that, Python will substitute those in. In modern versions of Python (**), you don't need to specify positional arguments in the format command, meaning the following are equivalent:

[code]'{} and {}'.format("spam", "eggs")[/code][code]'{0} and {1}'.format("spam", "eggs")[/code]Both yield the string, 'spam and eggs'. By changing the numbers instead to 1 and 0, we get 'eggs and spam'. So if the positional arguments are not set, then they will be in the order that you specify them in the format command.

Do note, that if you do specify positional arguments but you index a non-existent entry (say, by typing in a 2 instead of 0 in our example), you will get an IndexError.

Formatting numbers:

So now that we have handled text, how do we handle numbers in our format command?

In python, we have several options on how we can handle numbers. These are
'e' - print the number in exponent notation, using e to indicate the exponent.
'E' - same as e, but use E instead.
'f' - displays a number as a fixed point number.
'F' - same as 'f' but nan (not a number) is displayed as NAN and inf (infinity) is displayed as INF.
'g' - general format. For a given precision >=1, round the number to p significant figures and then format using 'f' or 'e' depending on the magnitude of the number. +/-infinity, +/-0 and not a number is formatted as inf, -inf, 0, -0 and nan. (***)
'G' - similar to g but use E if the number is too large. Also capitalizes inf and nan.
'n' - uses the current locale to insert the appropriate number separator characters, but otherwise the same as g.
'%' - percentage.
none - similar to 'g' but when fixed point notation is used the number has at least one digit past the decimal point.

Simple example: truncating pi

As we all know, pi is approximately 3.14159265358979323846... . However, this takes up a lot of space. Let's make it 5 decimal places long:

[code]pidecimaldigits = 3.14159265358979323846
print("{:.5f}".format(pidecimaldigits))[/code]This yields the number 3.14159.

Returning to mfaktc - reproducing the format of a progress indicator

Armed with our knowledge, we can reproduce the progress line in mfaktc in Python.
Let's reproduce a simple line, with class, time, rate:
[code]Class = 348
time = 21.824
rate = 912.1
print("Class: {0}/4620, time: {1:.2f} s, GhZ-d/day: {2:.2f}".format(str(Class), time, rate))[/code]This yields the following:

[code]Class: 348/4620, time: 21.82 s, GhZ-d/day: 912.10[/code] (*) The options should be similar in the OpenCL equivalent, mfakto, as well as the Double Mersenne program, mmff. More information can be found [URL="https://mersenneforum.org/showthread.php?t=15646"]here,[/URL] [URL="https://mersenneforum.org/showthread.php?t=17162"] or here.[/URL]
(**) Applies for version 3.1+. In 3.4+ they can also be omitted for the Formatter, which is the class that contains the format command.
(***) More precise rules can be found at [URL]https://docs.python.org/3/library/string.html#format-specification-mini-language[/URL].

Dylan14 2019-11-19 02:24

If/else, part 1: the if command and the else command
 
Now that we have dealt with the print command and other related commands (such as the format command and the input command), it's time to move on to stuff that will form the backbone of many programs: loops and if/else statements.
We can classify these as follows:
* if/elif/else - We test if a logical statement (possibly a chain of logical statements) is true or not. If it is true, we execute something. If not, then depending on what we have following it, we will run something else.
* for loop - We have a counter (usually i, but it doesn't have to be). This is initialized to some value. The loop will iterate for some number of iterations. During one of these iterations, we do something.
* while - While a logical statement is true, we run whatever is in the loop. As soon as the logical is no longer true, we stop.

Loops will come later, after we deal with modules and functions. For now, we will focus on the first part of the list: if/else statements(*).

If/else statements:

In real life, we often do stuff based on whether certain conditions are true. For example (using mersenneforum's favorite program):

If the temperature is less than 40 degrees Fahrenheit, I will run Prime95 on my computers to warm the room.
Today's high temperature is 38 degrees.
Therefore, I will run Prime95 today.

Much like in real life, certain code will run if a certain condition is true or not. The way we can implement this in Python (and really any programming language) is to use if statements.
Systematically, the if statement works like this:

[CODE]if(expr):
dosomething()[/CODE]We will break this down further. The first line in the if statement reads "if(expr)". This is interpreted as follows: We test the truthiness of the expression inside the parentheses. There are two outcomes of testing the expression:
a) The expression evaluates True. If this is the case, then we evaluate whatever is in the body, which is everything after the colon (i.e., we do something). Note that whatever is in the block must be indented(**). If it isn't, you will get a IndentationError.
b) The expression evaluates False. If this is the case, then we skip over the code and move to the next piece of code, or we stop if this is the last piece of code.

If we want to implement our good piece of advice, we could type the following into our shell:

[CODE]temp = input("Enter a number")
if(float(temp) <= 40):
print("run Prime95")[/CODE]What this does is if the user enters a number, then we check if the input is less than or equal to 40. If it is, then we are told to run Prime95. If not, then we get nothing. If we don't get a number as input, then we get an error.

Now we only have one thing inside the block. We can of course have as many statements as we like inside the block. We can even have more if statements within the block, as long as we indent properly.

Now, say we want the code to do something else if our expression evaluates as false. We can do this by using else statements. Else statements must follow an if statement, they can't be alone. For example, if we type this in:


[CODE][FONT=&quot]else:[/FONT]
[FONT=&quot] print("hi")
[/FONT][/CODE]we will get a SyntaxError. Systematically, the if/else construct works like this:
[CODE]if(expr):
#code to run if expr is true
dosomething()
else: #code to run if expr is false
dosomethingelse()
[/CODE]Note the indentation!
So let's suppose that we have the computers off when the temperature is above 40 degrees. We can modify the code as follows:
[CODE]temp = input("Enter a number")
if(float(temp) <= 40):
print("run Prime95")
else: #temp > 40
print("Turn your computers off, it's warm out there!")[/CODE]Now, if the input is below 40, we run prime95. If not, then the input is either a number above 40, or it's something else. If it is a number, then we are told that we should keep our computers off. If it is something else, we will get an error.
A few more notes:
1) Expressions can be compounded using the operators "and" and "or". So we can have something like this for an if statement:
[CODE]if(expr1 and expr2): #evaluates if expr1 and expr2 are both true
dosomething()[/CODE]or this
[CODE]if(expr1 or expr2): #evaluates if expr1 or expr2 are true
dosomething()[/CODE]or something more complicated, like (expr1 and (expr2 or expr3)). Using "and" and "or", you can fine tune exactly when a piece of code runs.
2) You can write if/else expressions in a single line, and if you have multiple statements you want to run, then you separate with semicolons. For example, this is perfectly valid:
[CODE][FONT=&quot]temp = input("Enter a number: ")
if(float(temp)<=40): print('run Prime95'); print(str(temp))
[/FONT][/CODE]However, for complicated statements, this can be quite messy to read. I will avoid using this style, and just use the indents(***).
3) If you have an if or else statement with nothing in it, you will get an error:
[CODE]if(3 > 2):
[/CODE]yields a SyntaxError due to an unexpected end of file. To fix this, you can use the Pass command, which does nothing, but is included to ensure proper syntax. So this would be valid:

[CODE]if(3 > 2):
pass #don't do anything[/CODE]here, 3 is indeed bigger than 2, but we don't do anything, since we have the pass command inside the if block.

(*) The elif command is more useful for when we have more complicated logical chains, or when we are defining functions with recursion. We will cover this in the next section.
(**) As I have stated before, most text editors will have their own definition of an indent in Python. See the section "Basic Syntax" for more information.
(***) Even though they can be a pain to ensure they line up properly here.

Dylan14 2019-11-24 01:49

If/else, part 2: the elif command
 
In the last section, we learned about the if command and the else command. This allowed us to run a piece of code if a logical expression was true, and another thing if it was false. Now suppose instead we want to have more than two code snippets (for example, one if a logical expression is true, another one if that logical statement is false, but a second logical statement is true, and a third if both logical statements are false). We can do this by using the elif command.

The elif statement:

The elif statement works very much like the if statement. The statement has the following syntax:

[CODE]elif(expr):
dosomething()[/CODE]There is a few things to keep in mind when you use the elif command:

1. There must be an if statement prior to the first invocation of the elif statement. If you don't do this, or you have a bare elif statement, you will get a SyntaxError.
2. You can have as many elif statements as you want. You have to make sure that each of these have the same indent level as the if statement that precedes all of the them, or you will get a SyntaxError.
3. If there is a else statement, it must be after all elif statements.
4. The same syntax that applies for if and else applies for the elif statement.

Putting it all together:

With the if, else and elif statements, we can build the most general if statement that we can make in Python. This works as follows:

[CODE]if(expr1):
#code to run if expr1 is true
elif(expr2):
#code to run if expr1 is false, but expr2 is true
elif(expr3):
#code to run if expr1 and expr2 are false, but expr3 is true
.
.
.
elif(exprn):
#code to run if expr1, expr2, ..., exprnminus1 are false, but exprn is true
else:
#code to run if all n expressions are false[/CODE]Again, note the indentations.
With this construct, we can build recursion relations(*), or complex checks.
Example:

[CODE][FONT=&quot]#code to check the sign of a number
num = input("Enter an integer: ")
if(int(num) > 0):
print(str(num) + " is positive")
elif(int(num) == 0):
print(str(num) + " is zero")
else:
print(str(num) + " is negative")
[/FONT]
[/CODE]This code uses if, elif and else to test whether an integer is positive, negative or zero.
It's important to try limiting cases: try the following inputs:
2 (positive)
0 (zero)
-167 (negative)
b (an error should occur)

(*) Recursion relations can be defined in functions. We will cover these in a future section of the guide.

Dylan14 2019-12-06 23:49

Functions
 
So far we have dealt with some of the functions built into Python 3. We haven't touched all of the functions yet (we haven't dealt with for loops, the while function, slicing, file operations, etc.), but even with all of these functions, we are somewhat limited in what we can do with them. So, to supplement Python's abilities, we can do the following things:
a) Define functions that do a specific thing.
b) Import modules that extend the capabilities of the code.
Now modules may consist of many classes(*), each of which may have one or more functions. Hence, we will use this section to discuss about functions, how one may write a function, and a few examples.

Functions:

A function in Python isn't exactly like a function in mathematics (where you take a number, perform something on that number, and then get another number back). Rather, it's a block of organized code that performs a single action. There are two types of functions:
a) Built in functions - which we have been exclusively using so far
b) User defined functions
Now, the syntax for a function is the following:
[CODE]def name_of_function(args):
"doc string"
code that the function should run
return something[/CODE]Let's go through each of these items in turn:
* All functions must start with the keyword "def". This is then followed by the function name, and then a set of parentheses and a colon after the parentheses.
* Within the parentheses, we include all of the arguments that the function is allowed to take. It is possible to have a function that takes no arguments. We will cover the types of arguments in a moment.
* After the colon, an indented block starts. The next thing, which is optional, is the doc string. Usually this is encased in triple quotes. Also, this should hopefully tell the user what the function does.
* After the doc string comes the meat of the function. This is where the code that the function should run goes. This can be very simple, or it can involve very complex things with multiple loops.
* Once done, the function must include a return expression. The return expression may have 0 or more arguments. If it has 0 arguments, it is interpreted as return None.

Let's do a simple example now, before we move to recursive functions and a more detailed view of arguments.
Sum function:
This function takes two integers, a and b, and returns the sum of the two:
[CODE]def sum(a, b):
return a+b[/CODE]Now if we type
[CODE][FONT=&quot]a = 1
b = 3
sum(a, b)
[/FONT][/CODE]and execute in a new cell, we get 4, as we expect.

Recursive functions, and an example:

A recursive function is a function whose value is based on a previous value of the function. A couple of examples of these include:
* The Fibonacci sequence (0th term is 0, first term is 1, nth term is the sum of the previous two terms)
* The Lucas sequence (similar to the Fibonacci sequence but the first two terms are 2 and 1)
* The factorial function (0! = 1, 1! = 1, 2 = 2*1 = 2*1!, 3 = 3*2*1 = 3*2!, etc., so that n! = n*(n-1)!)
In Python, recursion can be done, by calling the function within the function with a different argument(**). To see this in action, let's code up the factorial function:
[CODE]def factorial(n):
#Computes the factorial of a positive integer
if n < 0:
raise ValueError("n must be zero or a positive integer")
elif n == 0:
return 1
elif n == 1:
return 1
else:
return n*factorial(n-1) #see the recursion![/CODE]Try this on the following n's:
0 - should get 1
1 - should get 1
3 - should get 6
.2 - should get an error as after the first recursion, n-1 = -.8 which is smaller than 0.

More on arguments:
As stated above, we stated that we have arguments within the parentheses for functions. There are 4 types of arguments:
*Required arguments
*Keyword arguments
*Default arguments
*Variable length arguments

A required argument must be placed in correct positional order. The number of arguments in the function call must match exactly with the way we defined it.
Going back to our function sum(a, b), we see that the sum function must take 2 arguments when we call it. If we don't have that many arguments, then we get an error.
If we go back to the cell that we defined a and b and we remove the b in the sum, we get the following:
[CODE]TypeError: sum() missing 1 required positional argument: 'b'[/CODE]Keyword arguments are related to the function call. When a keyword argument is used, the interpreter will identify the argument by their name. As such, we can put them out of order.
For example, in a cell after you ran the cell with the sum definition, run this:
[CODE]sum(b= 7, a = 2)[/CODE]this should yield 9.
Default arguments: These specify a default value for an argument that will be used if the argument is skipped.
Variable length arguments:
In some functions, you may find it useful to have a function that takes more arguments than you defined. These are known as a variable length argument, and these are not named in the function definition, like so:


[CODE]def name_of_function([args], *var_args_tuple):
"doc string"
code that the function should run
return something[/CODE]the * before a variable denotes a variable that holds all the nonkeyword variable arguments.
Lambda:
Lambda can be used to run an expression, but not a command or multiple expressions. I haven't used these, but they may prove useful to you (***).
The syntax is the following:

[CODE]lambda [args]:expression[/CODE]where args is a comma separated list of arguments. There can be as many arguments as you like.
Lambda is also limited to using only variables that are declared globally, declared within the class (if it is a class) or those in the parameter list.

(*) Classes are used to define an object and the properties of all objects that are in the class. This has a clear analogue to C/C++ classes. As this requires more things to come together, we will cover this later.
(**) Care must be taken that you don't write a function that doesn't terminate.
(***) This is no longer the case. I used this to make a simple parse function that reads the data from [URL="http://wttr.in"]wttr.in[/URL] for a qtile config.

Dylan14 2019-12-21 20:18

Modules and packages
 
So we have mentioned that functions and classes are the backbone of modules, which are used to extend the abilities of Python. So what exactly are modules, and how can we add some to Python?
A module is an object which is a organizational unit of Python code. Each of these have a namespace which contains other objects (such as functions, variables and other objects). These can be used within a Python program, but they first must be imported first. Related to modules are packages, which is actually a special type of module that can contain submodules, or subpackages (*). To use these, one must first download the package and then import the necessary modules within the package.

Getting and installing modules/packages:

To install a module or package, one must first ensure that pip is installed in your Python distribution. This shouldn't be a problem as the main installer of Python (see post 3, How to Get/Use Python) includes this. If you are using a distribution of Python, it may include a package manager which one can use to install packages. For example, the Anaconda distribution of Python has a utility called Anaconda navigator, which provides a GUI for package installation/upgrading. If you are using a Linux distro version of Python, you may need to install pip. This can be done in Ubuntu and similar flavors as follows (entering your password if needed):

[CODE]sudo apt-get install python3-pip[/CODE]or on Arch and derivatives:

[CODE]sudo pacman -S python-pip[/CODE]Once you have pip installed, you can then go to the Python Package Index ([URL]https://pypi.org/[/URL]) and search for packages. When you have found a package, you can install it by typing the following on a command line:

[CODE]python -m pip install NameofPackage[/CODE]or on Linux (**)(***)

[CODE]pip install NameofPackage[/CODE](****)

This will yield the following, for example:

[CODE]dylan@ubuntu:~/Desktop$ python3 -m pip install numpy
Collecting numpy
Downloading https://files.pythonhosted.org/packages/9b/af/4fc72f9d38e43b092e91e5b8cb9956d25b2e3ff8c75aed95df5569e4734e/numpy-1.17.4-cp37-cp37m-manylinux1_x86_64.whl (20.0MB)
100% |████████████████████████████████| 20.0MB 58kB/s
Installing collected packages: numpy
The scripts f2py, f2py3 and f2py3.7 are installed in '/home/dylan/.local/bin' which is not on PATH.
Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed numpy-1.17.4
[/CODE]If you want to upgrade a package, you can do so using the following:
[CODE]pip install --upgrade NameofPackage[/CODE]and you can also remove packages using the --uninstall option. Further information on pip syntax can be found at [URL]https://pip.pypa.io/en/latest/reference/[/URL].

Importing and using a module

Once you have downloaded a package, we can then import it into our program, so that the objects that are in the package/module within the package can be called(*****). There are three ways to do this

1. import ModuleName
2. import ModuleName as ShortName
3. from ModuleName import "comma separated list of functions, or *"

1. This is the simplest way to import a module, as it will give you all the functions in one go. The downside is that you have to call the full name of the module every time you want to use something from it (i.e. ModuleName."chain of submodules, period separated".function(args))
2. With this, you can shorten the length of calls to functions. You have to preface a call to a function within a module with "ShortName.".
3. With this, you can select the functions that you specifically want, or you can use the asterisk to import everything in the module. The upside is that you don't need to preface a function call with anything before calling the function. The downside is that you may have conflicting function definitions. Think of this like the struct "using namespace std" in C/C++.
Note that the as function can also be used to rename functions when importing, provided you are doing one function at a time (i.e. from Module import Function as FunctionName, in generic terms).

An example:

Let's try to compute the matrix inverse of the following matrix:
[TEX]\begin{bmatrix}
1 & 2\\
3 & 4
\end{bmatrix}[/TEX]

To do this, we can use the inv function in numpy.linalg(6). We'll show how to call this in the 3 ways we did above.

1. Using import only:
[CODE][FONT=&quot]import numpy
a = numpy.array([[1.,2.],[3.,4.]])
ainv = numpy.linalg.inv(a)
ainv
[/FONT][/CODE]2. Using import with as:
[CODE][FONT=&quot]import numpy as np
a = np.array([[1.,2.],[3.,4.]])
ainv = np.linalg.inv(a)
ainv
[/FONT][/CODE]3. Using the from command (with the as command as well):
[CODE][FONT=&quot]import numpy as np[/FONT]
[FONT=&quot]from numpy.linalg import inv
[/FONT][FONT=&quot]a = np.array([[1.,2.],[3.,4.]])
ainv = inv(a)
ainv[/FONT][/CODE]All of these yield the same thing:
[CODE]array([[-2. , 1. ],
[ 1.5, -0.5]])[/CODE]or in fancy LaTex:
[TEX]\begin{bmatrix}
-2 & 1\\
1.5 & -0.5
\end{bmatrix}[/TEX]

(*) Actually, a package is any module that has the __path__ attribute.
(**) Some packages may be available in the distro repository. Try, for example,
[code]sudo apt-get install python3-numpy[/code]to install numpy in Ubuntu or Debian or
[code]sudo pacman -S python-numpy[/code]on Arch (provided it is in the main repos. If it is in the AUR, it's a bit more complicated, so I would advise reading the Arch Wiki on [URL="https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_and_upgrading_packages"]the method to build packages manually[/URL] or using a AUR helper like [URL="https://aur.archlinux.org/packages/yay"]Yay,[/URL] [URL="https://aur.archlinux.org/packages/trizen/"]trizen[/URL] or [URL="https://aur.archlinux.org/packages/pikaur/"]pikaur, which is written in Python[/URL].
(***) In some other distros packages might already be included when you install. An example is ArcoLinux, which by default on a fresh install has numpy installed.
(****) When you execute this command, pip may install additional packages that the package you selected needs in order to run. These are known as dependencies.
(*****) If the module that you want to use is on the list provided [URL="https://docs.python.org/3/py-modindex.html"]here[/URL], you don't need to download it as Python includes these by default. If not, you will need to download the package first before you import, otherwise you will get a ModuleNotFoundError.
(6) We'll cover numpy in more detail later.

Dylan14 2019-12-25 00:52

For loops part 1: Introduction to for loops
 
So far, we covered one part of the backbone of programs: the if/else/elif statements. Now we move to loops. A loop (in coding lingo) is a sequence of statements which is specified once, but can be run many times, even an infinite number of times. There are several types of loops:
* for loops (run a piece of code x number of times, and we keep track of how many times we run the code with a counter)
* while loops (while some boolean statement is true, run a piece of code and break out when the statement is no longer true)
* for each loops (run a piece of code on every single item in a collection of objects)
* do...while loops (run a block of code at least once, and then repeat the block depending on the truth value of a statement at the end of the block)
For the next couple of sections, we will deal with the for loop.

For loop syntax:
The for loop in Python has the following syntax:
[CODE]for <variable> in <iterable object>:
do something[/CODE]Here, <variable> is known as the iterator. The iterable object can be a list, a string, a tuple, or any object which can be iterated over(*). After this, we follow with a colon and then an indented block starts. Inside the indented block is code that should be iterated over, through all the objects in the iterable object.
Some notes here:
1. The object that we are iterating over must be iterable. You can't iterate over an integer, otherwise you will get a error.
2. The indented block must have something, it can't be empty. Like with the if/else construct, you can use the pass function if you don't want to run anything inside the loop.
3. You can have nested for loops. In this case the inner-most loop will iterate through, then (if you've coded things correctly) the next inner loop will iterate and the innermost one will reset, and so on.
A simple example:

Let us print out the exponents that are known to produce Mersenne Primes (which is used in several programs, like dmdsieve). We can do this using a for loop:
[CODE]exp_list = ['2', '3', '5', '7', '13', '17', '19', '31', '61', '89', '107', '127', '521', '607', '1279', '2203', '2281', '3217', '4253', '4423', '9689', '9941', '11213', '19937', '21701', '23209', '44497', '86243', '110503', '132049', '216091', '756839', '859433', '1257787', '1398269', '2976221', '3021377', '6972593', '13466917', '20996011', '24036583', '25964951', '30402457', '32582657', '37156667', '42643801', '43112609', '57885161', '74207281', '77232917', '82589933']
for exp in exp_list:
print(exp)[/CODE]Here, we are iterating over a list called exp_list, and our variable is called exp (**). For each item in the list, we print it.
This is an example of a for each loop, even though in Python we are simply using for and in.

The range function:

Say we want to run a loop a certain number of times. To do this, we can use the range function. The syntax of the function is as follows:

[CODE]range(start, stop, step)[/CODE]The function requires one argument, stop, and start and step are optional. The arguments do the following things:
start - specifies the start of the sequence. By default, this is 0.
stop - a required argument, which specifies the upper bound of the sequence. This number is not included in the range.
step - specifies the difference between each result. By default, this is 1.
A few notes:
Start, stop and step must be integers.
The arguments can be negative or positive.
Step has to be non-zero, otherwise you will get a ValueError.
A simple example with range:
[CODE]x = range(6)
for i in x:
print(i)[/CODE]which yields:
[CODE]0
1
2
3
4
5[/CODE] so you can see that 6 is not included.

Slightly more complicated example with range, with start and step
[CODE]y = range(-1,12,3)
for i in y:
print(i)[/CODE]which yields:
[CODE]-1
2
5
8
11[/CODE]The next increment, which would be 14, is greater than 12 and therefore is not printed.
There are similar functions included in numpy called arange and linspace which deal with arrays. We will deal with these later when we mention numpy.

Factorial, revisited:
Recall that when we covered functions we defined the factorial function, using if, else and elif. We can do a similar thing with for loops, with a few if's to cover some of the unit cases (***):
[CODE]def factorial(n):
fac = 1
if n < 0:
raise ValueError("Factorial is defined for positive integers.")
if n == 0:
return fac
for i in range(n,0,-1):
fac = fac*i
return fac[/CODE]Note here we use all the arguments of the range function. As a test, try the following inputs:
0 - should get 1
1 - should get 1
3 - should get 6
.2 - should get a TypeError

(*) Most things in Python can be made iterable (even functions!). We will deal with this (as well as the iter function) later.
(**) Actually, it doesn't matter what I call the iterator. I just need to note that whatever I call it, I must use that throughout that code block.
(***) An important thing to do when testing code is to run it on some unit cases. For example, for the factorial function, we should test it on 0, since 0! is defined to be one.

Dylan14 2020-01-09 02:13

For loops part 2: The break and continue commands
 
So far, we just dealt with how for loops work on a high level, and we constructed a few ways to set up a loop (namely, using either an iterable object or a range object). But say we want to control a loop more succinctly, and in particular, we want to have a way to "escape". This can be done using the break and continue commands. We will apply these to an example that is very prevalent at mersenneforum: trial factoring of Mersenne numbers.

The break command:

Break is a very simple command: it breaks out of a loop (which can be a for loop or a while loop (*)). The syntax is as follows:

[CODE]break[/CODE]In psuedocode, this would look like this:

[CODE]#stuff before the loop
for object in a sequence:
#stuff to run in the loop
if condition:
break
#then jump out the loop and then go to the next piece of code outside the loop
#stuff following the break statement

#stuff after the loop[/CODE]If one has a nested for loop, then a break will terminate the loop in which it appears, and move to the next iteration of the next inner loop.
Example of a break statement - one loop:
[CODE]string = "mersenneforum"
for i in string:
if i != "s":
print(i)
else:
break[/CODE]What this does is checks if a character in the string is not s. If it is not s, we print the character. Otherwise, we break out of the loop, and since nothing follows, execution stops.
Nested loops and break:
[code]characters = "abcdefghijklmnopqrstuvwxyz"
for i in range(6):
print("Outer loop iteration:" + str(i))
for j in characters:
print(j)
if j == "c":
print("Inner loop interrupted...")
break
[/code]This code runs the outer loop, which prints the current iteration, and then the inner loop runs, which prints the alphabet up to c, and at that point the inner loop breaks, and we go to the next iteration of the outer loop.

The continue command:

The continue command is similar to the break command, but instead of leaving the loop, we skip whatever is left in the body of the loop and start the next iteration.
In psuedocode:
[code]#stuff before the loop
for object in a sequence:
#stuff to run in the loop
if condition:
continue
#then go to the beginning of the code block in the loop
#stuff after the continue statement
#stuff after the loop
[/code]The syntax is the same as with break.
Example with continue:
[CODE]string = "mersenneforum"
for i in string:
if i != "n":
print(i)
else:
continue[/CODE]Here, we check if the character is not n, and if it is not, we print the character. Otherwise, we go to the next letter in the string. The result is that we get all the characters in mersenneforum, one character at a time, except for the two n's in that.

An application: Mersenne trial factoring:
We can use for loops, the continue statement, and the break statement to create a simple program to trial factor Mersenne numbers (**).
First, some facts that we can use:
1. Factors of Mersennes must have the form 2*k*p+1, where p is the exponent, which is a prime number.
2. The factor must be 1 or 7 (mod 8). This reduces the search space quite a bit.
So how can we implement this? Well, the first statement tells us that we could iterate through all k's from some lower bound to some upper bound, via a for loop.
The second statement states that we should check if q = 2*k*p+1 is 1 or 7 mod 8 and if it isn't, discard it.
So we can code this:
[CODE]#A simple trial factor program for Mersennes
p = input("Enter a prime number: ")
mer = 2**int(p)-1
mink = 1
maxk = 10000000
for k in range(mink, maxk+1): #test all k's from mink to maxk
#candidate factor is in the form 2*k*p+1
candidate = 2*k*int(p)+1
#check if the candidate is 1 or 7 (mod 8)
if candidate%8 == 1 or candidate%8 == 7:
#divide the mersenne number by the candidate and see if it factors it
if mer%candidate == 0: #the candidate divides the mersenne
print("M" + str(p) + " has a factor: " + str(candidate))
break
else:
#if not, go to the next k
continue[/CODE]This code first requests an exponent from the user. The program then generates the Mersenne number corresponding to that exponent, and then for all k's running from kmin to kmax, it first creates the corresponding candidate factor, tests if it is 1 or 7 mod 8 and if it is, checks if it divides the mersenne. If it does, it prints the factor to the screen and breaks. If not, it continues until it finds a candidate that works, or it reaches the end of the range.
Test on a known factor:
[CODE]Enter a prime number: 7112003
M7112003 has a factor: 355600151[/CODE]corresponding to k = 25 (see [URL]https://www.mersenne.ca/exponent/7112003[/URL]).

(*) We will cover while loops in the next section.
(**) Note I say simple, not fast. If you want speed, I recommend either using prime95/mprime if you have an x86_64 processor, mfactor from the mlucas suite if you have an ARM processor, factor5 for higher Mersenne's, mfaktc/mfakto for GPU's, or mmff, dm or dmdsieve + pfgw/LLR for Double Mersennes.

Dylan14 2020-01-10 01:53

While loops
 
In the last two sections, we covered for loops, which allows us to run a loop for a certain number of times. But say we want to run a piece of code if some condition is true. To do this, we can use a construct called the while loop.

The while loop:

The syntax of the while loop is as follows:
[code]while [a condition is true]:
do something
[/code]The condition must be a boolean statement, or it can be the elements True or False. If a boolean statement is given, then the program will evaluate the boolean statement and only evaluate the body of the loop if it evaluates True. If the element True is encountered, then the code block will continue forever (*). If the element False is encountered, then the code will not execute, as False is never True.
A simple example:
Let's sum the first ten positive integers. We can do this in a while loop:
[CODE]sum = 0
i = 1
while i<=10:
sum = sum + i
i += 1
print(sum)[/CODE]So, we first initialize a variable sum to 0 and i to 1. While i is less then or equal to 10, we add i to sum, and increment sum. Internally, sum goes as follows: 1, 3, 6, 10, 15, 21, 28, 36, 45, 55. Once we ran through the loop 10 times, i is 11. But 11 > 10, so we skip the loop, and then print the sum, which is 55.

Infinite loops:

An infinite loop occurs in a while loop only, since as we recall, for loops only run until the iterable object is exhausted. We can create an infinite loop by creating a condition that cannot ever be false, for example:

[CODE]while(True):
do something[/CODE]Of course, you should be careful with what you put into such a loop, as you don't want to end up running out of memory because you are trying to enumerate all the primes in a loop (**). There is a couple of things that this construct would be useful:
1. You are trying to monitor something on your computer, like CPU usage or GPU usage (***).
2. You are running a server and you want the server to run continuously so that clients can attach to it, communicate, and then detach at will.
3. You are running a DC project which can be left running for long periods of time.

Now, of course we can use break and continue to control while loops, which can be useful in infinite loops(****).
Example - Pascal's triangle
Pascal's triangle is a triangular array of the binomial coefficients, which are defined as follows:

[TEX]{n\choose k} = \frac{n!}{k!(n-k)!}[/TEX]

Using while loops, we can compute the rows forever, however, using break, we will terminate after row 5 (*****):
[CODE]i = 0
while(True):
print("Row " + str(i+1))
for j in range(i+1):
entry = int((factorial(i))/(factorial(j)*factorial(i-j)))
print(str(entry))
i += 1
if i > 4:
break[/CODE]This yields each of the first 5 rows of Pascal's triangle. Of course, we can change the number of rows that we print out by changing the number in the second to last line in the above code snippet (6).
Alternatively, if we want to do the same thing without break, this works:
[code]i = 0
while(i <= 4):
print("Row " + str(i+1))
for j in range(i+1):
entry = int((factorial(i))/(factorial(j)*factorial(i-j)))
print(str(entry))
i += 1[/code]What about do... while loops?

When I mentioned loops in the first part of the for loop discussion, we mentioned that there is a thing called do while loops, where you do something at least once, and then you repeat if the truth value of the statement is true. Now Python does not have this construct (in stark contrast to C, C++, and Java), but you could emulate this. Here's a possible way to do this:
[code]i = 5
while(True):
#do something
i -= 1
if i == 0:
break
[/code]Basically, we run something (the do statement), and then we decrement i, and then we run again (the "while" statement is true) until i = 0, and then we stop (the "while" statement is false).

(*) Well, forever in the sense that the code will continue to run until either one of the following happens:
1. There is an error that is encountered, which automatically stops execution,
2. Ctrl+C is pressed, which is the keyboard interrupt,
3. Some other thing happens which causes the code to stop executing (Windows update, BSOD, kernel panic, power outage, time limit exceeded in a Colab/Kaggle session, etc.).
(**) I wish you good luck if you want to do that.
(***) This is possible, see for example the [URL="https://pypi.org/project/gpustat/"]gpustat[/URL] package on PyPi.
(****) There are other things that we can use; for example, the command sys.exit(). We will cover the sys module later.
(*****) You will need to use the factorial function that I created, either in Part 1 of for loops, or in the section on functions.
(6) Just don't delete the last 2 lines, otherwise, you will not stop.

Dylan14 2020-01-12 01:44

Putting it all together
 
Now that we have learned about if, else, elif, for and while, we can go on and try to work with all of these to build programs. We'll do a few examples, one of which is an OEIS sequence.

Example: OEIS A003599:

[URL="https://oeis.org/A003599"]OEIS A003599[/URL] lists all numbers of the form 7^i*11^j for i and j non negative. The terms are given as 1, 7, 11, 49, 77, 121, etc., corresponding to the (i, j) values of (0,0), (1,0), (0,1), (2,0), (1,1), (2, 0), respectively. The listings goes up to 5764801, which is 7^8*11^0. Now, how can we code this?
1. We need two variables, i and j. They should both start at 0.
2. Since the limit of the sequence shown on the page is 5764801 (*), we should limit ourselves to, say, 6000000.
So we could first use a for loop to loop over i, and then while we are under the limit, we print i, j, and the resulting number.
So let's code it.
First, we should define a function to compute the numbers:
[CODE]def numform(i, j):
#computes 7^i*11^j
return (7**i)*(11**j)[/CODE]Next, we develop the main loop: we iterate over i in a for loop, and then we test if 7^i*11^j is smaller than our bound. If it is, we then print the tuple (i, j), and the resulting number, and then we increment j. Otherwise, we set j = 0, and increment i. This is coded as follows:
[CODE]j = 0
for i in range(0,11): #test all i's from 0 to 10
#if 7^i*11^j is smaller than a certain bound (namely, 6000000), print i, j and the resulting number
while numform(i,j) <= 6000000:
print("(" + str(i) + ", " + str(j) + "), " + str(numform(i,j)))
j += 1
else:
j = 0[/CODE]When we do this, we get the following output:
[CODE](0, 0), 1
(0, 1), 11
(0, 2), 121
(0, 3), 1331
(0, 4), 14641
(0, 5), 161051
(0, 6), 1771561
(1, 0), 7
(1, 1), 77
(1, 2), 847
(1, 3), 9317
(1, 4), 102487
(1, 5), 1127357
...[/CODE]which does correspond to the entries in A003599.
By changing the appropriate things in the code, you can recreate the following sequences in OEIS: A003591-A003599. I'll leave it as an exercise to do that.

Using else in for and while loops:

In our code for A003599, we used else after a while loop, which we would usually use after an if statement. But we were able to use else after a while loop, within a for loop in Python. This is actually unique to Python. The following happens when you use else with a loop:
* If else follows after a for loop, then the code that is in the else block runs once the code exhausts the iterable object that the for loop is operating on.
* If else follows after a while loop, then the code that is in the else block runs once the condition that governs the while loop becomes false.
To see this in action, let's go back to the code we wrote for A003599. With the code that we used and the bounds that we set, we get results all the way up to i = 8. If, instead, we excluded the else block, we get the following output:

[CODE](0, 0), 1
(0, 1), 11
(0, 2), 121
(0, 3), 1331
(0, 4), 14641
(0, 5), 161051
(0, 6), 1771561[/CODE]so we only get the lines with i = 0, as then j is not reduced afterwards from 7. Then, clearly 11^7 = 19487171 is larger than our bound of 6000000, so we increment i. But when we increment i, we will get an even bigger number. So we never get another number that is smaller than our bound, so the output stops.

Example: Logging in (**)

Many websites require you to log in in order to get use all the functionality of the site. Such logins usually involve a username and a password (and occasionally some two factor authentication). Sometimes sites (like Mersenneforum) will only allow you to try x number of times before locking you out for a short period of time. How can we implement this?
1. We set up a password (here we will use a plain string). Usually, it is encrypted and salted on the server. However this is beyond the scope of this section.
2. While we have not exceeded the number of attempts, we ask the user to supply the password.
3. If it is correct, then we break out of the loop.
4. If it is incorrect, then we tell the user "wrong password, try again", and increment the attempts by 1.
5. If the maximum number of attempts have been made, then we lock the user out (here we'll just print a message).
Here's the code:
[CODE]#Passwords and logging in
password = "passw0rd"
i = 1
while i <= 3: #3 attempts
#ask for input
inputtedpassword = input("Enter your password: ")
if inputtedpassword == password:
#log in
print("Logging in...")
break
else:
#warn user, ask them to try again
print("Wrong password, try again")
i += 1
else:
#lock user out
print("You have been locked out. Try again later")[/CODE]This does work, but I would advise not using this code for your website. It is meant to be a proof of concept (***)

(*) The b-file goes a lot higher than this, but we want to just recreate the terms on the main sequence page.
(**) This checks against a plain string, which is in the code. Needless to say, you should NEVER have passwords in plain sight (for obvious reasons).
(***) Python does have a getpass module, which enables the password to be hidden when typing it in. That is the least of my concerns with using this (see point (**) above).

Dylan14 2020-07-19 21:46

Strings part 2 - indexing, repeating, and slicing
 
So far, we have dealt with the concept of strings, the fact that we can concatenate them, and using the format command to change how the string appears when outputted. But there are other things we can do with strings:
1. We can index the characters within a string with an index.
2. We can repeat a string multiple times.
3. We can slice a string, to extract only a certain part of the whole string.
There are other useful things, which I will mention briefly in the next section. More details can be found in the Python documentation, or elsewhere.
But first, let's revisit multiline strings:

Multiline strings:

Recall when I wrote about multiple line comments, I had an example as follows:
[code]
"""
Some comments need
more than one line,
like this one
""" [/code]This is actually a valid string, as can be evidenced when I type this into an interpreter:
[code]>>> msg = """Some comments need
more than one line,
like this one
"""
>>> print(msg)
Some comments need
more than one line,
like this one
[/code]In general, to do a multiline string like this, you would need to encase the 'stuff' in either triple double quotes ("""stuff""") or triple single quotes ('''stuff'''). Alternatively, you could use a single line string, and the escape sequence '\n' to start a new line, as follows:

[code]>>> msg2 = "The rain in Spain \nfalls mainly on the plain."
>>> print(msg2)
The rain in Spain
falls mainly on the plain.[/code]Indexing and slicing strings:

Like other languages, strings are arrays of bytes representing characters.

Unlike other languages, such as C, Python does not have a character data type (*). Instead, characters are just strings with length one.
Since the string is an array, I can index the elements of the string. A couple of notes:
1. Indexing starts from 0, which denotes the first character.
2. As a corollary of this, you can only go to the index n-1, which is the last character in the string. If you go beyond this, you will get an IndexError.
3. You can use negative indices. In this case you will index from the last character in the string, and work backwards. Here the furthest back you can go is -n, which is the first character in the string.

Examples:

Let's consider the following single line string:
[code]The rain in Spain falls mainly on the plain.[/code]To ensure that we don't get an IndexError, we will use the len command, which gives the length of the string.
[code]>>> msg3 = "The rain in Spain falls mainly on the plain."
>>> len(msg3)
44[/code]With this, the valid indices are -44 to 43.
1. Let's pick out the S in Spain. We count from 0, which is the T in the. 1 - h, 2 - e, 3 - space, 4 - r, 5 - a, 6 - i, 7 - n, 8 - space, 9 - i, 10 - n, 11 - space, 12 - S. So msg3[12] should be S. Let's check:
[code]>>> print(msg3[12])
S[/code]2. Alternatively, let's go backwards. -1 - ., -2 - n, -3 - i, ..., -32 - S. So msg3[-32] should also be S. Let's check:
[code]>>> print(msg3[-32])
S[/code]3. What happens if we try index 50?
[code]>>> print(msg3[50])
Traceback (most recent call last):
File "<pyshell#18>", line 1, in <module>
print(msg3[50])
IndexError: string index out of range[/code]We get an error, as 50 > 43.

Slicing a string:
Now, we will use indices to get a piece of the string. Slicing uses colons, and have three arguments, all of which have to be integers.
1. The first number denotes the initial index.
2. The second number denotes the final index.
3. The third number denotes the step. This can't be 0, and by default is 1 (meaning, print all characters between the initial index and the final index).
If you have at least one argument, the rest are optional. This goes as follows:
By default, the first argument is 0 (start at the beginning of the string), the second argument is len(string) - 1 (the end of the string) and the third argument is 1.

Examples: Again, let's consider the following string:
[code]The rain in Spain falls mainly on the plain.[/code]1. Let's take the 7th through 15th characters in the string:
[CODE]>>> msg4 = "The rain in Spain falls mainly on the plain."
>>> print(msg4[6:14])
in in Sp[/CODE]2. Let's print the 5th character from the end to the end of the string:
[code]>>> print(msg4[-5:])
lain.[/code]3. Let's print every third character of the string:
[code]>>> print(msg4[::3])
T iiSiflmn eln[/code]Here, the final index that's printed in 42. The next jump, 45, is outside the range.

Repeating a string:
One can "multiply" a string, or more correctly, repeat a string, by using the * symbol. The syntax looks like the following:
[code] int * "stuff"[/code]where 'int' is a positive integer and "stuff" is a string (**).

Example:

The usual battle of people in Misc. Math here goes as follows:
1. Some crank spews some garbage.
2. The intelligent people in the forum debunks said garbage.
3. The cycle repeats until the thread is locked or the crank leaves.

Let's describe it in a bit of Python:

[code]>>> msg5 = "garbage, debunk, "
>>> print(3 * msg5 + "then the thread ends.")
garbage, debunk, garbage, debunk, garbage, debunk, then the thread ends.[/code] (*) The module ctypes can be imported to give Python a C compatible char data type. But by default Python does not have a character data type.
(**) Actually, you can use a negative integer or 0 for the integer. But nothing will print.

Dylan14 2020-07-19 21:46

Miscellaneous string operations
 
(placeholder)

Dylan14 2020-10-24 18:10

Introduction to lists
 
(placeholder)


All times are UTC. The time now is 14:33.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.