A document from MCS 275 Spring 2022, instructor David Dumas. You can also get the notebook file.

Python tour - MCS 275 Spring 2022 - David Dumas

This is a "quick" tour of Python syntax and features that students can use as a reference. It is a written version of live coding examples from Lectures 2-3 of the course. It isn't completely systematic, and it doesn't include every detail of the language that is usually covered in prerequisite courses of MCS 275, but is meant to provide a way to refresh your memory of some of the most important Python features. The optional course texts or the course materials from MCS 260 provide more detailed information.

Scripts vs REPL vs notebooks

You can run the python interpreter using the interpreter name, usually python or python3. It waits for commands to run, and prints the result of each one. This is the REPL.

You can run a whole file of Python code using python FILENAME.py or python3 FILENAME.py (depending on the interpreter name).

This document is a notebook, which is more like the REPL. Pieces of code appear in cells, and the value of the last expression in the cell is printed in the output. We'll introduce notebooks properly in a future MCS 275 lecture, so for now you can just treat this as a nice way to present many small programs to you.

Variables, assignment, basic types

In [1]:
# Create a variable by assignment.  No separate declaration needed.
x = 5

# What's the value of x now?
In [2]:
# Change the value of x a few times; it can change types at any time
x = 10 # a different integer value
x = 3.25 # a float
x = True # a boolean
x = None # None (the null value)
x = "hello" # a string
# AVOID TYPE CHANGES IN MOST CASES as they make programs harder for humans to understand.
In [3]:
# Some integers
1_000_000 # one million (_ is a separator that is ignored, like a comma)
0x1e # hexadecimal
0b1001 # binary
# only the last value in a cell appears in the output, so you should see 9 = 0b1001 below
In [4]:
# Some floats
3e6 # three million.  "e" is for exponent, means 3 * 10**6
In [5]:
# The only possible values of a boolean.  Note capitalization
False # Output will only show this one; it's the last value in this cell
In [6]:
# The only value of type `nonetype` is None.  It is used as a "null", a signal of the absence of something.
# Displaying a None in the REPL doesn't display anything at all, so this cell has no output
In [7]:
# Some strings.  Can use " or ' for single-line strings, or """ or ''' for multi-line strings
"2021"  # This isn't a number!  It is in quotes, so it is a string
"It was the best of times"
'It was the worst of times'
"""It was time for MCS 275 lecture
but I didn't zoom installed on my
"It was time for MCS 275 lecture\nbut I didn't zoom installed on my\nlaptop."


In [8]:
# addition
In [9]:
# multiplication
In [10]:
# division yields a float, even if the result is an integer
In [11]:
# exponentiation is **, and not ^ which is used for this in some other languages

The order of operations follows the mnemonic PEMDAS:

  • Parentheses
  • Exponents
  • Multiplication and division (equal precedence)
  • Addition and subtraction (equal precedence) Operations with the same precedence will be done in left-to-right order.
In [12]:
10 / 2 / 5  # The leftmost division is done first, so this becomes (10/2) / 5 which is 1
In [13]:
# modulus (remainder upon division) is %
1271845 % 7  # This number is one more than a multiple of 7

Operations on strings

In [14]:
# Join two strings
"hello" + " world"
'hello world'
In [15]:
# Repeat a string many times using multiplication
"n" + ( "o"*30 )

Boolean expressions and logic

In [16]:
# Compare numbers with <, >, =, <=, >=
1 < 5
In [17]:
27 >= 27
In [18]:
27 > 27
In [19]:
# Equality is tested with ==
8 == 9
In [20]:
# Strings compare by dictionary order, with < meaning earlier in dictionary
"aardvark" < "abalone"
In [21]:
"skunk" < "shark"
In [22]:
# Capital letters come before lower case letters in this dictionary
"Zebra" < "airplane"

Numeric conversions

In [23]:
# Convert a string to an integer
In [24]:
# Convert string to integer, using a base other than 10
int("1001",2) # base 2 = binary, so we get 0b1001 = 9

String conversions

In [25]:
# Convert anything to a string with str()
# Not often needed.  But for example you could use this to 
# get the digits of an integer, since a string lets you
# access individual characters
In [26]:
In [27]:
str([2,7,5])  # Lists are formatted with spaces after the commas
'[2, 7, 5]'

Useful features of strings

In [28]:
s = "Hello"
# Convert to upper case (returns the converted value, doesn't change s)
In [29]:
# Convert to lower case
In [30]:
# Test for prefix
In [31]:
# Test for suffix
In [32]:
# "string in string" tests for the presence of a substring
"car" in "racecar"
In [33]:
"aaa" in "banana"
In [34]:
# String formatting: .format(value, value, ...) formats the values and puts them into the string where
# there are placeholders

# Basic usage
"I wish I had a pet {} so they could eat {} {}".format("mouse",16,"seeds")
'I wish I had a pet mouse so they could eat 16 seeds'
In [35]:
# Placeholders can have numbers to indicate which of the arguments they should take
# They are 0-based indices of the list of arguments to .format(...)
"First you put on your {1}, and THEN you put on your {0}".format("shoes","socks")
'First you put on your socks, and THEN you put on your shoes'
In [36]:
# Floating point placeholders can have a formatting directive in the format :X.Yf
# where X,Y are integers. The number will be formatted to have a width of at least X characters,
# Y of them after the decimal point.  X is optional.
"I am {:3.2f} percent sure of it".format(75.12345)
'I am 75.12 percent sure of it'
In [37]:
"Rounding to tenths we find that pi is approximately {:.1f}".format(3.14159265359)
'Rounding to tenths we find that pi is approximately 3.1'

Printing stuff

In a script, you won't see any output if your program just contains expressions, because in script mode, Python doesn't print the results of evaluating each line. You need to explicitly request output.

In [38]:
# Display a message in the terminal
print("Hello world")
# Note: This statement doesn't return a value!
Hello world
In [39]:
# Can print multiple values.  They'll be separated by spaces, by default
print("What if I told you that MCS",275,"was fun?")
# print() can handle every built-in type
print("Here is a list:",[5,4,3,1])
What if I told you that MCS 275 was fun?
Here is a list: [5, 4, 3, 1]
In [40]:
# print() puts a newline at the end by default
# This can be disabled
print("ba",end="")   # no newline after this one

List basics

Lists are mutable ordered collections of elements accessible by integer index. They are similar to arrays in other languages.

In [41]:
# Lists are written with square brackets and commas
[2, 7, 5]
In [42]:
# Elements of a list can have different types.
# Let's set up an example to work with in the next few cells.
L = [ 1, "fish", 2, "fish", False, True, False, None, 5.25, "last"]
In [43]:
# Retrieve an element of a list using brackets with 0-based index.
L[0]  # first element
In [44]:
L[3]  # fourth element
In [45]:
# Negative index means count from the end of the list, with -1 meaning last element
In [46]:
# len(listname) gives the length of the list `listname`

List slices

In [47]:
# Let's set up a sample list to work with (same one used in a previous section)
L = [ 1, "fish", 2, "fish", False, True, False, None, 5.25, "last"]
In [48]:
# Select a contiguous sublist using [start_idx:end_idx]
# Includes the element at start_idx, but not end_idx
# This is an example of a "slice"
L[2:5]  # Has 5-2 = 3 elements
[2, 'fish', False]
In [49]:
# Slices that extend past the end of the list don't produce an error
L[5:100000]  # Elements 5 to 99999 requested, but we get 5 to 9
[True, False, None, 5.25, 'last']
In [50]:
# Slices start at the beginning if the start index is missing
L[:3] # first three elements
[1, 'fish', 2]
In [51]:
# Slices end at the end if the end index is missing
L[3:] # everything but the first three elements
['fish', False, True, False, None, 5.25, 'last']
In [52]:
# You can specify that a slice should use a step size other than 1
L[::2]  # Every other element, starting at index 0
[1, 2, False, False, 5.25]
In [53]:
L[1::2]  # Every other element, starting at index 1
['fish', 'fish', True, None, 'last']

List conversion and membership testing

In [54]:
# Convert a string to a list to get a list of its characters
['a', 'b', 'c', 'd', 'e', 'f']
In [55]:
# Let's set up a sample list to work with (same one used in a previous section)
L = [ 1, "fish", 2, "fish", False, True, False, None, 5.25, "last"]
In [56]:
# Checking whether an item is an element of a list
5.25 in L
In [57]:
2 in L
In [58]:
"ball" in L

Other useful list features

In [59]:
# set up a list to work with
courses_taken = [ 260, 275 ]
# Add an element at the end with append
courses_taken.append(320) # doesn't return anything, it just modifies the list
In [60]:
# What's in the list now?
[260, 275, 320]
In [61]:
# An element of a list can be replaced using item assignment
courses_taken[0] = 261  # change first element to 261
In [62]:
courses_taken # Now, the first element should be 261
[261, 275, 320]
In [63]:
# But you can't add new elements to the list with item assignment
# Only existing elements can be modified
courses_taken[3] = 501  # no item 3 right now, so this gives an error.
IndexError                                Traceback (most recent call last)
<ipython-input-63-7f114ccb9050> in <module>
      1 # But you can't add new elements to the list with item assignment
      2 # Only existing elements can be modified
----> 3 courses_taken[3] = 501  # no item 3 right now, so this gives an error.

IndexError: list assignment index out of range
In [64]:
# .pop() will remove and return the last element of a list
In [65]:
# Notice that 320 is no longer in the list
[261, 275]
In [66]:
# .index(elt) will find elt and return its position
# or raise an exception if it is not found
courses_taken.index(275)  # should return 1 since courses_taken[1] is 275
In [67]:
# .insert(where,what) adds an element at a specific position
# Afterward, listname[where] will be equal to `what`
# Existing items in the list remain, but move to higher indices
# to make room (if needed).
courses_taken.insert(1,401) # Put 401 at index 1, i.e. make it the second element.
courses_taken # Show the resulting list
[261, 401, 275]
In [68]:
# Sort a list in place
courses_taken.sort() # note lack of any return value
In [69]:
# But after the previous command, the list is now sorted
[261, 275, 401]

String indexing

In [70]:
# Strings also support integer indices and slices to get characters or substrings
In [71]:
In [72]:
"banana"[1::2]  # every other letter 
In [73]:
# Reverse a string
In [74]:
# Similar to lists, you can get the total number of characters in a string with len(...)
len("If you have a garden and a library, you have everything you need.")


Map keys to values. Keys can be of various types (but some restrictions, e.g. lists cannot be keys). Values can be arbitrary types. Written with {} and : to separate key from value.

In [75]:
# Create a dictionary and bind the name "d" to it
d = { "department": "MSCS", "building": 631, "phd_granting": True}
In [76]:
# Access the value associated with a key
In [77]:
# Add a new key-value pair to the dictionary
d["college"] = "LAS"
In [78]:
# Test if a **key** is present
"building" in d # True because "building" is a key of this dict
In [79]:
# You can't use `in` to directly check if a value is present
631 in d  # False because 631 is not a key of this dict

Conditionals: if-else-elif

In [80]:
if 5 > 7:
    print("5 is larger")
    print("7 is larger")
7 is larger
In [81]:
x = 15 # adjust this number and run the code to test other branches
if x % 6 == 0: 
    print(x,"is divisible by 6")
elif x % 3 == 0:
    print(x,"is divixible by 3, but is NOT divisible by 6")
    print(x,"is not divisible by 3 (and so not by 6 either)")
15 is divixible by 3, but is NOT divisible by 6
In [82]:
s = "carpeting"  # change this word and run the code to test conditional
if "pet" in s:
    print(s,"contains pet as a substring")
    print("In fact, it appears at index",s.find("pet"))
carpeting contains pet as a substring
In fact, it appears at index 3


In [83]:
# Find a power of 2 that has 7 as a digit
n = 1
while "7" not in str(2**n):
    n = n + 1
# The next line is not indented, so it only runs when the loop is finished
print("Found it: The number 2**{} = {} has 7 as a digit".format(n,2**n))
Found it: The number 2**15 = 32768 has 7 as a digit
In [84]:
# Take each element of a list and print it
available_drinks = ["coffee","tea","juice"]
for drink in available_drinks:
    print("Available drink:",drink)
Available drink: coffee
Available drink: tea
Available drink: juice
In [85]:
# Take each key of a dictionary and do something with it
dept_data = { "department": "MSCS", "building": 631, "phd_granting": True}
for field in dept_data:
    print("{} = {}".format(field,dept_data[field]))
department = MSCS
building = 631
phd_granting = True
In [86]:
# Dictionaries support retrieving key,value pairs
# which can be unpacked into two variables in a loop
for field,value in dept_data.items():
    print("{} = {}".format(field,value))
department = MSCS
building = 631
phd_granting = True
In [87]:
# Break out of a loop early with `break`
L = [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 ]
for x in L:
    if "5" in str(x):
        # if we hit an integer containing digit 5, we stop the loop
print("The loop ended, so the next element of L must have contained the digit 5")
The loop ended, so the next element of L must have contained the digit 5


Be careful: It can be dangerous to run file-related commands, because opening a file for writing will delete any existing file with that name. It is important to make sure that any time you open a file for writing, the filename does not refer to an existing file whose contents you want to keep!

In [88]:
# Open a new file (delete if it exists already) for writing
output_file = open("output.txt","wt") # wt = write, text (not binary) file
# Write some text to it.  Note need to add our own newlines.
output_file.write("This is a text file.\n")
output_file.write("That is all.\n")
# Close the file (writes may not actually happen until now)
In [89]:
# Open the file created above, for reading
input_file = open("output.txt","rt")
# Get everything in the file as a single string
s = input_file.read()

# Now print what we read from the file
This is a text file.
That is all.

In [90]:
# Process lines of that file one by one
input_file = open("output.txt","rt")

for line in input_file:
    print("I just read one more line from the file.  The contents are:")
    print(line,end="")  # line will already have a newline, most likely
    print("This line of the file has {} characters\n".format(len(line)))

I just read one more line from the file.  The contents are:
This line of the file has 7 characters

I just read one more line from the file.  The contents are:
This is a text file.
This line of the file has 21 characters

I just read one more line from the file.  The contents are:
That is all.
This line of the file has 13 characters

In [91]:
# Reading is a one-time operation.  Trying to read file contents twice
# gives no data the second time.
input_file = open("output.txt","rt")
s1 = input_file.read()  # Read everything, after which we're at the end of the file
s2 = input_file.read()  # Reads nothing, already at the end of the file

print("The first time I read from the file I got:")
print("The second time I read from the file I got:")
print(s2)  # will print nothing, because we read nothing
print("(Expect nothing shown above, since we're already at the end of this file.)")
The first time I read from the file I got:
This is a text file.
That is all.

The second time I read from the file I got:

(Expect nothing shown above, since we're already at the end of this file.)


In [92]:
# In Python, any text after the symbol # on a line is ignored.  This is a comment.
# There is no multi-line comment syntax in Python; you just put # in front of each.

x = 1  # You can also put comments on the same line as code

# And # it is ok # for comments to contain # any number of # characters.

Use comments to explain code, making it easier for humans to understand.

Usually, a good comment doesn't just say what a line of code is doing, but explains why.

A complete lack of comments is bad. Excessive comments are also bad, especially when they state the obvious. (This review document, which is expository and written for students relatively new to Python, has a number of comments that would be considered excessive/obvious in other contexts.)

In [93]:
# EXAMPLE OF EXCESSIVE COMMENTS - they describe code that is already clear
for i in range(10):   # i from 0 to 9
    x = i*i  # compute the square of i and store in x
    print("Square:",x)  # display the square just computed
Square: 0
Square: 1
Square: 4
Square: 9
Square: 16
Square: 25
Square: 36
Square: 49
Square: 64
Square: 81
In [94]:
import math

L = []
for i in range(2,30):
    for j in range(2,math.floor(math.sqrt(i))+1):
        if i % j == 0:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
In [95]:
"""Find the primes up to 29 by the naive (inefficient) method"""
import math # For sqrt

L = [] # to hold the primes
for i in range(2,30):
    L.append(i) # Add i to the list of primes for now; will remove later if composite
    # If i is composite, then one of its divisors is less than or equal to the
    # square root of i, so we need only check up to that point for divisors.
    for j in range(2,math.floor(math.sqrt(i))+1):
        if i % j == 0:
            # Now we know i is composite (divisible by j), so remove it from L and
            # exit the inner loop, moving on to the next prime candidate.
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]


In Python, the first statement in a file, function body, or class definition should be a string literal on a line by itself. It should contain a description of the file, function, or class. This is called a docstring.

While having a string on a line by itself does nothing in Python, in these cases (first statement of file, function, class), Python will store the string and make it available as part of the built-in help.

Most explanatory text in a Python program should be in comments. Docstrings go in just a few special places, and describe a file, class, or function.

In [96]:
# Suppose this cell contains the full contents of hello.py
# Print a greeting    <--- this describes the file, but it isn't a docstring!  Not a string literal
# "Print a greeting"  <--- also not a docstring.  It's a comment, not a string literal
"""Greet the user"""   # <--- THIS IS A DOCSTRING
"""by saying hello"""  # BAD! Not a docstring, as it isn't the first statement.
                       #      It should be a commend instead

# Comment line in the middle of the file.  That's fine.

print("Hello user!")
Hello user!
In [97]:
# This example involves functions.  See the next section for details about functions.

def f(x):
    """Compute the 'smoothstep' polynomial at x and return."""  # <--- DOCSTRING (even without this comment)
    return 3*x**2 - 2*x**3

print("f({}) = {}".format(0.1,f(0.1)))
f(0.1) = 0.028000000000000004
In [98]:
# Retrieve help about f(...), which includes the docstring.
Help on function f in module __main__:

    Compute the 'smoothstep' polynomial at x and return.


Functions provide reusable, named (usually) code blocks that can be called (run) at any point in a program, can accept data from the program, and can return data.

In [99]:
# Basic example

def clamp(x):
    """Clamp x between 0 and 1, i.e. if x is less than 0, return 0.
       If x is greater than 1, return 1.  Otherwise return x."""
    if x<0:
        return 0.0
    if x>1:
        return 1.0
    return x

for i in range(17):      # iterate over 0...16
    t = (i / 10) - 0.3   # so t ranges from -0.3 to 1.3, with steps of size 0.1
    print("clamp({:.2f}) = {:.2f}".format(t,clamp(t)))
clamp(-0.30) = 0.00
clamp(-0.20) = 0.00
clamp(-0.10) = 0.00
clamp(0.00) = 0.00
clamp(0.10) = 0.10
clamp(0.20) = 0.20
clamp(0.30) = 0.30
clamp(0.40) = 0.40
clamp(0.50) = 0.50
clamp(0.60) = 0.60
clamp(0.70) = 0.70
clamp(0.80) = 0.80
clamp(0.90) = 0.90
clamp(1.00) = 1.00
clamp(1.10) = 1.00
clamp(1.20) = 1.00
clamp(1.30) = 1.00
In [100]:
# Functions can take multiple arguments, which are required if no default value is given
def clamp2(x,minval,maxval):
    """Clamp x between minval and maxval"""
    if x<minval:
        return minval
    if x>maxval:
        return maxval
    return x

for i in range(11):   # iterate over 0...10
    t = (i / 10)     # so t ranges from 0 to 1, with steps of size 0.1
    print("clamp2({:.2f},0.2,0.8) = {:.2f}".format(t,clamp2(t,0.2,0.8)))
clamp2(0.00,0.2,0.8) = 0.20
clamp2(0.10,0.2,0.8) = 0.20
clamp2(0.20,0.2,0.8) = 0.20
clamp2(0.30,0.2,0.8) = 0.30
clamp2(0.40,0.2,0.8) = 0.40
clamp2(0.50,0.2,0.8) = 0.50
clamp2(0.60,0.2,0.8) = 0.60
clamp2(0.70,0.2,0.8) = 0.70
clamp2(0.80,0.2,0.8) = 0.80
clamp2(0.90,0.2,0.8) = 0.80
clamp2(1.00,0.2,0.8) = 0.80
In [101]:
# Default values can be specified, and if they are, the argument is optional.
def clamp3(x,minval=0.0,maxval=1.0):
    """Clamp x between minval (default 0) and maxval (default 1)"""
    if x<minval:
        return minval
    if x>maxval:
        return maxval
    return x

print("clamp3({:.2f}) = {:.2f}".format(t,clamp3(-0.2)))  # minval, maxval get default values
print("clamp3({:.2f},-1,1) = {:.2f}".format(t,clamp3(-0.2,-1,1)))  # minval, maxval specified
clamp3(1.00) = 0.00
clamp3(1.00,-1,1) = -0.20
In [102]:
# When calling a function, you can specify arguments by name using name=value syntax
# These *keyword arguments* or *kwargs* can appear in any order, whereas arguments
# given as values alone must appear in the same order as the definition.

print(clamp3(minval=0.4,x=0.3))  # Using kwargs to choose the argument order

# kwargs are really useful for functions with many arguments, most of which have default
# values.  Often you want to call them and change just a few arguments from defaults.
In [103]:
# Functions don't need to return anything.  If the `return` keyword is not used,
# the function returns None

def hello():
    """Print a friendly greeting"""
    print("Hello there!")

hello() == None  # True, because no return means return None
Hello there!


Modules allow you to put a bunch of code in a separate file so it can be reused and is contained (allowing it to be used without the user worrying about all the details). Splitting code for a large program between multiple files also makes it easier to browse the source and to maintain the program.

In [104]:
#%%writefile polynomials.py
# Example module
# To actually use this, either:
#     1) Save the entire cell contents in a file "polynomials.py"
# or  2) Remove the # in front of the first line of this cell and run in a notebook
"""Some useful polynomials and other functions"""

USEFUL_CONST = 1234.0   # all caps is *not* required

def nozeros(x):
    """A quadratic polynomial with no real zeros"""
    return x**2 + 1

def smoothstep(x):
    """Smoothstep polynomial (clamped between 0 and 1)"""
    if x<0:
        return 0.0
    if x>1:
        return 1.0
    return 3*x**2 - 2*x**3
In [105]:
"""Example of using the polynomials module"""
# (Won't work unless you've saved the cell above to polynomials.py in the same directory where
#  you are running this code.)

import polynomials

print(polynomials.nozeros(0.2)) # should be 1.004
print(polynomials.smoothstep(0.45)) # should be 0.42525
In [106]:
# There are many useful modules in the Python standard library
# A few examples follow

import sys
print(sys.version) # Python version
print(sys.argv[0]) # Name of the currently running script
3.8.5 (default, Jul 28 2020, 12:59:40) 
[GCC 9.3.0]
In [107]:
import time

time.sleep(1.25) # Wait for 3.1 seconds

print("It is now {} seconds since 0:00 on Jan 1 1970 GMT".format(time.time()))
It is now 1610652081.4329822 seconds since 0:00 on Jan 1 1970 GMT
In [111]:
import os

print("Files in the current directory:")
for fn in os.listdir("."):

# Check for a file that exists (for the instructor developing this worksheet)
if os.path.exists("output.txt"):
    print("A file with name '{}' exists in the current directory.".format("output.txt"))

# Check for a file that does not exist
if os.path.exists("worksheet1soln.ipynb"):
    print("A file with name '{}' exists in the current directory.".format("worksheet1soln.ipynb"))
Files in the current directory:
A file with name 'output.txt' exists in the current directory.


In Python, classes provide a way to define custom types that combine attributes (data) and methods (behavior).

They are the basis of object-oriented programming in Python.

Classes can extend other classes, allowing customization of certain properties while reverting to the parent class behavior on others.

In [109]:
# Basic 2D point class
import math # for sqrt

class Point:
    """A point in the xy-plane"""  # DOCSTRING
    def __init__(self,x,y):
        """Initialize new point instance"""
        self.x = x
        self.y = y
    def translate(self,dx,dy):
        """Move the point by a vector (dx,dy)"""
        self.x += dx
        self.y += dy
    def distance_to(self,other):
        """Distance from this point to another one"""
        deltax = other.x - self.x
        deltay = other.y - self.y
        return math.sqrt(deltax**2 + deltay**2)

P = Point(3,4)  # Creates instance of Point, which calls __init__(...)
print("Distance from (3,4) to the origin: {:.2f}".format(P.distance_to(Point(0,0))))
print("Before moving: P.x={}, P.y={}".format(P.x,P.y))
print("Moving by (5,1)")
P.translate(5,1)  # Modifies P, returns nothing!
print("After moving:  P.x={}, P.y={}".format(P.x,P.y))
Distance from (3,4) to the origin: 5.00
Before moving: P.x=3, P.y=4
Moving by (5,1)
After moving:  P.x=8, P.y=5
In [110]:
# Class help includes docstrings of the class itself and its methods
Help on class Point in module __main__:

class Point(builtins.object)
 |  Point(x, y)
 |  A point in the xy-plane
 |  Methods defined here:
 |  __init__(self, x, y)
 |      Initialize new point instance
 |  distance_to(self, other)
 |      Distance from this point to another one
 |  translate(self, dx, dy)
 |      Move the point by a vector (dx,dy)
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  __weakref__
 |      list of weak references to the object (if defined)