# Continue one line with '\'

# Continue multiple lines with parenthetical expression '(...)' (preferred)

# Separate multiple statements on one line with ';'

# All variables are pointers (including ints)

# Everything is an object (including ints)

# null
x = None

# create a requirements.txt
$ pip freeze > requirements.txt

# confirm TensorFlow sees the GPU
from tensorflow.python.client import device_lib
assert 'GPU' in str(device_lib.list_local_devices())

# confirm Keras sees the GPU
from keras import backend
assert len(backend.tensorflow_backend._get_available_gpus()) > 0

# confirm PyTorch is using the GPU
from torch import cuda
assert cuda.is_available()
assert cuda.device_count() > 0

# list
[1, 2, 3]

# tuple
(1, 2, 3)
1, 2, 3

# dict
{'a':1, 'b':2, 'c':3}

# set
{1, 2, 3}

# Tuples are immutable.

# Indexing, slicing, and many other list functions work on tuples.

# set operations
primes | odds <=> primes.union(odds)
primes & odds <=> primes.intersection(odds)
primes - odds <=> primes.difference(odds)
primes ^ odds <=> primes.symmetric_difference(odds)

# other useful collections (there are still more)
collections.namedtuple  # Like a tuple, but each value has a name
collections.defaultdict # Like a dictionary, but unspecified keys have a user-specified default value
collections.OrderedDict # Like a dictionary, but the order of keys is maintained

if x == 0:
    print(x, "is zero")
elif x > 0:
    print(x, "is positive")
elif x < 0:
    print(x, "is negative")
    print(x, "is unlike anything I've ever seen...")

for N in [2, 3, 5, 7]:
    print(N, end=' ') # print all on same line

for i in range(10):
    print(i, end=' ')

# range object
list(range(5, 10))
list(range(0, 10, 2))

i = 0
while i < 10:
    print(i, end=' ')
    i += 1



# define functions with def
def f(val):
    return ('f', val)

Functions can have default arguments.

Functions can be called using named arguments.

# varargs - the significant things are the '*' and '**' modifiers
def catch_all(*args, **kwargs):
    print("args =", args)
    print("kwargs = ", kwargs)

# lambda statement - functions are objects too
add = lambda x, y: x + y
    add(1, 2)

# sort list of dict alphabetically by first name
sorted(data, key=lambda item: item['first'])

    print("try something here")
    print("this happens only if it fails")
    print("this happens only if it succeeds")
    print("this happens no matter what")

raise RuntimeError("fail")

    x = 1 / 0
except ZeroDivisionError as err:
    print("Error class is:  ", type(err))
    print("Error message is:", err)

# define a custom exception
class MySpecialError(ValueError):
raise MySpecialError("here's the message")

# zip
for lval, rval in zip(L, R):
    print(lval, rval)

# map
for val in map(square, range(10)):
    print(val, end=' ')

# filter
is_even = lambda x: x % 2 == 0
for val in filter(is_even, range(10)):
    print(val, end=' ')

# unzip
z = zip(L1, L2)
new_L1, new_L2 = zip(*z)

# The itertools module contains permutation, combination and product functions.

# "ternary operator"
val if val >= 0 else -val

# list comprehensions - [expr for var in iterable]
[i for i in range(20) if i % 3 > 0]

# set comprehension
{n**2 for n in range(12)}

# dict comprehension
{n:n**2 for n in range(6)}

# generator expression
(n**2 for n in range(12))

# to print a generator expression
list(n**2 for n in range(12))

A generator is used up after one iteration.

Generator functions return values with 'yield'.

# requires all imported functions to be prefixed with package name
import math
import numpy as np

# imported functions can be used w/o prefix
from math import cos, pi
from math import *

# standard libraries
os and sys - Tools for interfacing with the operating system, including navigating file directory structures and executing shell commands
math and cmath - Mathematical functions and operations on real and complex numbers 
itertools - Tools for constructing and interacting with iterators and generators 
functools - Tools that assist with functional programming 
random - Tools for generating pseudorandom numbers
pickle - Tools for object persistence: saving objects to and loading objects from disk 
json and csv - Tools for reading JSON-formatted and CSV-formatted files 
urllib - Tools for doing HTTP and other web requests

# Common tools include numpy, scipy, pandas, matplotlib, scikit-learn.

# typecast

# remove item from list
del student_names[2]

# catch all exceptions
    x = 1 / 0
except Exception:

# converting a list to a set removes duplicates and sorts it
set([3, 2, 3, 1, 5]) == (1, 2, 3, 5)

def save_file(student):
        f = open("students.txt", "a")
        f.write(student + "\n")
    except Exception:
        print("Could not save file")

def read_file():
        f = open("students.txt", "r")
        for student in f.readlines():
    except Exception:
        print("Could not read file")

# There are no access modifiers.  All class methods and members are public.

# By convention, methods are marked "private" by preceding them with an underscore.

# There are no interfaces.

os.path.join(string, string)

import os
import tarfile
from six.moves import urllib

HOUSING_PATH = os.path.join("datasets", "housing")
HOUSING_URL = DOWNLOAD_ROOT + "datasets/housing/housing.tgz"

def fetch_housing_data(housing_url=HOUSING_URL, housing_path=HOUSING_PATH):
    if not os.path.isdir(housing_path):
    tgz_path = os.path.join(housing_path, "housing.tgz")
    urllib.request.urlretrieve(housing_url, tgz_path)
    housing_tgz =

# booleans can be added
True + True == 2

# read in CSV into a list of dict
import unicodecsv
with open(enrollments_filename, 'rb') as f:
    reader = unicodecsv.DictReader(f)
    enrollments = list(reader)

# clear the display in a jupyter notebook
from IPython.display import display, clear_output

# download an image
import requests
from PIL import Image
from io import BytesIO
r = requests.get(url)
i =