Difference between revisions of "Python:Common Mistakes"

From PrattWiki
Jump to navigation Jump to search
m (added variable problems and some method problems)
(Added subsection on Python Printing)
 
(20 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
==Overview==
 
==Overview==
  
This page is designed as a resource for new programmers learning Python for [http://pundit.pratt.duke.edu/wiki/EGR_103/Spring_2020 EGR 103]. If you are an experiencing an error with which you are not familiar, check the common mistakes below first.
+
This page is designed as a resource for new programmers learning Python for [http://pundit.pratt.duke.edu/wiki/EGR_103/Spring_2020 EGR 103]. If you are experiencing an error with which you are not familiar, check the common mistakes below first.
  
 
==Problems with Variables==
 
==Problems with Variables==
Line 8: Line 8:
  
 
===Assignment vs. Accessing===
 
===Assignment vs. Accessing===
When a variable starts a line and is immediately followed by a single equals sign, that variable is being assigned a new value. Most other situations involve accessing that variable but not directly modifying its value.
+
When a variable starts a line and is immediately followed by a single equals sign, that variable is being <B>assigned</B> a new value. Most other situations involve accessing that variable but not directly modifying its value.
  
<syntaxhighlight lang=python line>
+
<syntaxhighlight lang=python>
#PLACEHOLDER
+
In [1]: x = 1
 +
 
 +
In [2]: y = 2
 +
 
 +
In [3]: x = y
 +
 
 +
In [4]: print("x equals {}".format(x))
 +
x equals 2
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
Note that in the code above, <code>x = y</code>, <B>accesses</B> the value of y and <B>assigns</B> it to x. The variable which is being assigned a new value is always on the left.
  
 
===Calculating in a Vacuum===
 
===Calculating in a Vacuum===
The result of a calculation must always be stored or otherwise delivered to a method handler. The code below initially results in no change to variable x.
+
The result of a calculation must always be stored or used somehow, or else it has no effect. The code below on input line 3 results in no change to variable x.
 +
 
 +
<syntaxhighlight lang=python>
 +
In [1]: x = 0
 +
 
 +
In [2]: print("x equals {}".format(x))
 +
x equals 0
 +
 
 +
In [3]: x + 2
 +
Out[3]: 2
 +
 
 +
In [4]: print("x equals {}".format(x))
 +
x equals 0
 +
 
 +
In [5]: x = x + 2
  
<syntaxhighlight lang=python line>
+
In [6]: print("x equals {}".format(x))
x = 0
+
x equals 2
print("x equals {}".format(x))   #x equals 0
 
x + 2
 
print("x equals {}".format(x))    #x equals 0
 
x = x + 2
 
print("x equals {}".format(x))    #x equals 2
 
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
Note that after calling <code>x + 2</code>, the value of x doesn't change from zero, because the result of the calculation is never stored. After storing it in x with <code>x = x + 2</code>, x becomes 2.
 +
 +
===Renaming Keywords/Reserved words and Existing Variables===
 +
There are some words called [https://docs.python.org/3/reference/lexical_analysis.html#keywords keywords] (or reserved words in some other languages) that are variables that already exist in Python. For example, <code>for</code> and <code>ord</code> are both keywords. While Python allows you to use these as ordinary variable names, doing so is invariably a bad idea.
 +
 +
<syntaxhighlight lang=python>
 +
In [1]: x = 1
 +
 +
In [2]: y = 2
 +
 +
In [3]: sum = x + y
 +
 +
In [4]: z = sum(x, y)
 +
TypeError: 'int' object is not callable
 +
</syntaxhighlight>
 +
 +
<code>sum</code> is a keyword for a function that returns the sum of 2 arguments or of a list. Declaring it as a variable overwrites this function. If you accidentally name a variable the same as a keyword, you will need to click <B>Remove all variables</B>.
 +
 +
See also: [http://pundit.pratt.duke.edu/wiki/Python_Common_Mistakes#Variable_Explorer Variable Explorer]
  
 
===Pointers and Data Types===
 
===Pointers and Data Types===
For lists and other non-primitive data types, variables act as pointers to the data in memory. In the code below, y points to the same data as x in memory. By modifying the first element (0th index) of list y, x is also inadvertently changed because x points to the same location in memory.
+
For lists and other non-primitive data types, variables act as <B>pointers</B> to the data in memory. In the code below, y points to the same data as x in memory. By modifying the first element (0th index) of list y, x is also inadvertently changed because x points to the same location in memory. ''Note that this does not hold true for primitive data types like ints.''
 +
 
 +
<syntaxhighlight lang=python>
 +
In [1]: x = [1,2]
 +
 
 +
In [2]: y = x
 +
 
 +
In [3]: print("x equals {}".format(x))
 +
x equals [1, 2]
 +
 
 +
In [4]: print("y equals {}".format(y))
 +
y equals [1, 2]
 +
 
 +
In [5]: y[0] = 3
 +
 
 +
In [6]: print("x equals {}".format(x))
 +
x equals [3, 2]
  
<syntaxhighlight lang=python line>
+
In [7]: print("y equals {}".format(y))
x = [1, 2]
+
y equals [3, 2]
y = x
 
print("x equals {}".format(x))    #x equals [1, 2]
 
print("y equals {}".format(x))    #y equals [1, 2]
 
y[0] = 3
 
print("x equals {}".format(x))   #x equals [3, 2]
 
print("y equals {}".format(x))    #y equals [3, 2]
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
===Mutable and Immutable Data Types===
 
===Mutable and Immutable Data Types===
Unlike lists and numpy arrays, tuples and strings are not mutable in Python. The following code throws type errors on 5 and 6.
+
Unlike lists and numpy arrays, <B>tuples</B> and <B>strings</B> are not mutable in Python. The following code throws type errors on 5 and 6.
 +
 
 +
<syntaxhighlight lang=python>
 +
In [1]: x = (1, 2)
 +
 
 +
In [2]: y = "hello"
 +
 
 +
In [3]: print("x equals {}".format(x))    #x equals (1, 2)
 +
 
 +
In [4]: print("y equals {}".format(y))    #y equals hello
 +
 
 +
In [5]: x[0] = 3                         
 +
TypeError: 'tuple' object does not support item assignment
  
<syntaxhighlight lang=python line>
+
In [6]: y[3] = "m"                         
x = (1, 2)
+
TypeError: 'tuple' object does not support item assignment
y = "hello"
 
print("x equals {}".format(x))    #x equals (1, 2)
 
print("y equals {}".format(x))    #y equals hello
 
x[0] = 3                          #TypeError
 
y[3] = "m"                        #TypeError
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 55: Line 110:
  
 
===Printing vs. Returning===
 
===Printing vs. Returning===
Virtually all of the methods that you write in [http://pundit.pratt.duke.edu/wiki/EGR_103/Spring_2020 EGR 103] will include a return statement. The return statement will be the last line of code to run.
+
Virtually all of the methods that you write in [http://pundit.pratt.duke.edu/wiki/EGR_103/Spring_2020 EGR 103] will include a <B>return</B> statement. The return statement will be the last line of code to run.
  
 
<syntaxhighlight lang=python line>
 
<syntaxhighlight lang=python line>
Line 66: Line 121:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
While almost all methods will use a return statement, some will also include print statements. The two are not interchangeable. The code below will always return x+1, but it will only print x if x is positive.
+
While almost all methods will use a <B>return</B> statement, some will also include <B>print</B> statements. The two are not interchangeable. The code below will always return x+1, but it will only print x if x is positive.
  
 
<syntaxhighlight lang=python line>
 
<syntaxhighlight lang=python line>
Line 78: Line 133:
  
 
===Methods that Return and Methods that Modify===
 
===Methods that Return and Methods that Modify===
 +
Most methods that you will use in [http://pundit.pratt.duke.edu/wiki/EGR_103/Spring_2020 EGR 103] will <B>return</B> a value that you will process. The code below includes one such method.
 +
 +
<syntaxhighlight lang=python>
 +
In [1]: x = "1 2 3"
 +
 +
In [2]: y = x.split(" ")
 +
 +
In [3]: print("y equals {}".format(y))
 +
y equals ['1', '2', '3']
 +
</syntaxhighlight>
 +
 +
Occasionally, you will encounter a method that does not return a value, but which modifies the argument directly. The code below includes one such method.
 +
 +
<syntaxhighlight lang=python line>
 +
import numpy as np
 +
x = [1, 2, 3]
 +
np.random.shuffle(x)
 +
print("x equals {}".format(x))          #x equals [2, 3, 1]
 +
</syntaxhighlight>
  
 +
Always check the documentation when using a method. See also: [https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.random.shuffle.html numpy.random.shuffle]
  
 
==Miscellaneous==
 
==Miscellaneous==
Line 84: Line 159:
  
 
===For Loops vs. For-Each Loops===
 
===For Loops vs. For-Each Loops===
 +
The following code uses a <B>for-each loop</B> to access every <B>item</B> in a list and print its double.
 +
<syntaxhighlight lang=python>
 +
In [1]: x = [11, 22, 33]
 +
 +
In [2]: for item in x:
 +
  ...:    print(item * 2)
 +
  ...:
 +
22
 +
44
 +
66
 +
</syntaxhighlight>
 +
 +
The following code uses a <B>for loop</B> to iterate through each <B>index</B> in a list and then print 2 times the <B>item</B> at that index.
 +
<syntaxhighlight lang=python>
 +
In [1]: x = [11, 22, 33]
  
 +
In [2]: for index in range(len(x)):
 +
  ...:    print(index, x[index] * 2)
 +
  ...:
 +
0 22
 +
1 44
 +
2 66
 +
</syntaxhighlight>
  
 
See also: [http://pundit.pratt.duke.edu/wiki/Python:Iterative_Structures#Enumerated_Iterable Enumerate]
 
See also: [http://pundit.pratt.duke.edu/wiki/Python:Iterative_Structures#Enumerated_Iterable Enumerate]
  
 
===Testing Your Code===
 
===Testing Your Code===
 +
It is often useful to test the methods you write within the same script. One way of accomplishing this is to append the following code at the bottom of your script, calling any methods you've created, and then clicking <B>Run</B>.
 +
<syntaxhighlight lang=python line>
 +
def foo(x):
 +
    return x + 1
  
 +
if __name__ == '__main__':
 +
    print("foo returns {}".format(foo(0)))  #foo returns 1 
 +
</syntaxhighlight>
  
 
===Network Errors===
 
===Network Errors===
 +
Most assignments for [http://pundit.pratt.duke.edu/wiki/EGR_103/Spring_2020 EGR 103] require that your script is in the correct lab directory. Occasionally, Spyder will save your script to a different default location (e.g. Desktop). This will be indicated in the <B>Path</B>, at the top left corner of the Spyder window. In order for these scripts to access other files and to be imported into LaTeX, this Path should be very similar to what you seen when running <code>pwd</code> in [http://pundit.pratt.duke.edu/wiki/How_To_Get_Work_Done MobaXterm].
  
 +
If you are unable to connect to your virtual machine, ensure that (1) you are connected to Duke Blue, (2) you are entering your NetID and password correctly, and (3) you are running <code>ssh</code> with the <code>-XY</code> adverb.
  
 
===Variable Explorer===
 
===Variable Explorer===
 +
The <B>Variable explorer</B> is an invaluable debugging tool included within Spyder. By default, it is located in the top right of the Window, in the same box as <B>File explorer</B> and <B>Help</B>. By selecting it, you are able to view the Name, Type, Size, and Value of all variables you have declared during your current session.
 +
 +
By using <B>Run current cell</B> or <B>Run current line</B>, you can step through your code, tracking the value of variables in the Variable explorer to see if they match your expectations.
 +
 +
Occasionally, variables may share common names between scripts. If you notice you are receiving outputs wildly different from what you expect, you may find it useful to click <B>Remove all variables</B> (the eraser icon).
 +
 +
===Other Debugging===
 +
For additional debugging tips for Python and Spyder, see [https://pundit.pratt.duke.edu/wiki/Python:Debugging Python:Debugging].
  
 +
===Python Printing===
 +
If you're having trouble figuring out how to format strings, see: [https://www.python.org/dev/peps/pep-3101/#format-strings Format Strings], [https://www.python.org/dev/peps/pep-3101/#standard-format-specifiers Standard Format Specifiers], and [https://docs.python.org/2/library/string.html#format-specification-mini-language Format Specification Mini-Language].
  
===Renaming Existing Variables===
+
[[Category:EGR 103]]

Latest revision as of 22:15, 7 September 2020

Overview

This page is designed as a resource for new programmers learning Python for EGR 103. If you are experiencing an error with which you are not familiar, check the common mistakes below first.

Problems with Variables

These are problems involving the use, saving, and manipulation of variables, often encountered during the first half of the labs in EGR 103.

Assignment vs. Accessing

When a variable starts a line and is immediately followed by a single equals sign, that variable is being assigned a new value. Most other situations involve accessing that variable but not directly modifying its value.

In [1]: x = 1

In [2]: y = 2

In [3]: x = y

In [4]: print("x equals {}".format(x))
x equals 2

Note that in the code above, x = y, accesses the value of y and assigns it to x. The variable which is being assigned a new value is always on the left.

Calculating in a Vacuum

The result of a calculation must always be stored or used somehow, or else it has no effect. The code below on input line 3 results in no change to variable x.

In [1]: x = 0

In [2]: print("x equals {}".format(x))
x equals 0

In [3]: x + 2
Out[3]: 2

In [4]: print("x equals {}".format(x))
x equals 0

In [5]: x = x + 2

In [6]: print("x equals {}".format(x))
x equals 2

Note that after calling x + 2, the value of x doesn't change from zero, because the result of the calculation is never stored. After storing it in x with x = x + 2, x becomes 2.

Renaming Keywords/Reserved words and Existing Variables

There are some words called keywords (or reserved words in some other languages) that are variables that already exist in Python. For example, for and ord are both keywords. While Python allows you to use these as ordinary variable names, doing so is invariably a bad idea.

In [1]: x = 1

In [2]: y = 2

In [3]: sum = x + y

In [4]: z = sum(x, y)
TypeError: 'int' object is not callable

sum is a keyword for a function that returns the sum of 2 arguments or of a list. Declaring it as a variable overwrites this function. If you accidentally name a variable the same as a keyword, you will need to click Remove all variables.

See also: Variable Explorer

Pointers and Data Types

For lists and other non-primitive data types, variables act as pointers to the data in memory. In the code below, y points to the same data as x in memory. By modifying the first element (0th index) of list y, x is also inadvertently changed because x points to the same location in memory. Note that this does not hold true for primitive data types like ints.

In [1]: x = [1,2]

In [2]: y = x

In [3]: print("x equals {}".format(x))
x equals [1, 2]

In [4]: print("y equals {}".format(y))
y equals [1, 2]

In [5]: y[0] = 3

In [6]: print("x equals {}".format(x))
x equals [3, 2]

In [7]: print("y equals {}".format(y))
y equals [3, 2]

Mutable and Immutable Data Types

Unlike lists and numpy arrays, tuples and strings are not mutable in Python. The following code throws type errors on 5 and 6.

In [1]: x = (1, 2)

In [2]: y = "hello"

In [3]: print("x equals {}".format(x))    #x equals (1, 2)

In [4]: print("y equals {}".format(y))    #y equals hello

In [5]: x[0] = 3                          
TypeError: 'tuple' object does not support item assignment

In [6]: y[3] = "m"                        
TypeError: 'tuple' object does not support item assignment

Problems with Methods

These are problems involving the writing and use of methods, often encountered during the second half of the labs in EGR 103.

Printing vs. Returning

Virtually all of the methods that you write in EGR 103 will include a return statement. The return statement will be the last line of code to run.

1 def calc_adder(x):
2     print("x equals {}".format(x))    #x equals x
3     x = x + 1
4     print("x equals {}".format(x))    #x equals x+1
5     return x                          #returns x+1
6     x = x + 1                         #This line of code will never execute

While almost all methods will use a return statement, some will also include print statements. The two are not interchangeable. The code below will always return x+1, but it will only print x if x is positive.

1 def calc_adder2(x):
2     if (x > 0):
3         print("x equals {}".format(x))  #x equals x
4         print("x is positive")          #x is positive
5     x = x + 1
6     return x                            #returns x+1

Methods that Return and Methods that Modify

Most methods that you will use in EGR 103 will return a value that you will process. The code below includes one such method.

In [1]: x = "1 2 3"

In [2]: y = x.split(" ")

In [3]: print("y equals {}".format(y))
y equals ['1', '2', '3']

Occasionally, you will encounter a method that does not return a value, but which modifies the argument directly. The code below includes one such method.

1 import numpy as np
2 x = [1, 2, 3]
3 np.random.shuffle(x)
4 print("x equals {}".format(x))          #x equals [2, 3, 1]

Always check the documentation when using a method. See also: numpy.random.shuffle

Miscellaneous

These are other logic errors or configuration problems you may encounter, as well as some useful debugging practices.

For Loops vs. For-Each Loops

The following code uses a for-each loop to access every item in a list and print its double.

In [1]: x = [11, 22, 33]

In [2]: for item in x:
   ...:     print(item * 2)
   ...:
22
44
66

The following code uses a for loop to iterate through each index in a list and then print 2 times the item at that index.

In [1]: x = [11, 22, 33]

In [2]: for index in range(len(x)):
   ...:     print(index, x[index] * 2)
   ...:
0 22
1 44
2 66

See also: Enumerate

Testing Your Code

It is often useful to test the methods you write within the same script. One way of accomplishing this is to append the following code at the bottom of your script, calling any methods you've created, and then clicking Run.

1 def foo(x):
2     return x + 1
3 
4 if __name__ == '__main__':
5     print("foo returns {}".format(foo(0)))  #foo returns 1

Network Errors

Most assignments for EGR 103 require that your script is in the correct lab directory. Occasionally, Spyder will save your script to a different default location (e.g. Desktop). This will be indicated in the Path, at the top left corner of the Spyder window. In order for these scripts to access other files and to be imported into LaTeX, this Path should be very similar to what you seen when running pwd in MobaXterm.

If you are unable to connect to your virtual machine, ensure that (1) you are connected to Duke Blue, (2) you are entering your NetID and password correctly, and (3) you are running ssh with the -XY adverb.

Variable Explorer

The Variable explorer is an invaluable debugging tool included within Spyder. By default, it is located in the top right of the Window, in the same box as File explorer and Help. By selecting it, you are able to view the Name, Type, Size, and Value of all variables you have declared during your current session.

By using Run current cell or Run current line, you can step through your code, tracking the value of variables in the Variable explorer to see if they match your expectations.

Occasionally, variables may share common names between scripts. If you notice you are receiving outputs wildly different from what you expect, you may find it useful to click Remove all variables (the eraser icon).

Other Debugging

For additional debugging tips for Python and Spyder, see Python:Debugging.

Python Printing

If you're having trouble figuring out how to format strings, see: Format Strings, Standard Format Specifiers, and Format Specification Mini-Language.