# line comment
# Python consists of a sequence of logical lines made up of one or more
# physical lines.  (Blank lines and comments are ignored.)
i = 0
i = i + \
    1 # backslash allows continuation of a logical line on the next physical line
s = '''Triple-quoted strings can
run across multiple lines
verbatim.'''
i = (i +
     1) # Unmatches parens, braces, brackets, and triple quotes implicitly
        # continue logical lines.
print(i, s)
print(i, s, sep='')
# Indentation is how logical code block are defined. Precise indentation matters.
# A tab is not equivalent to several spaces.
if i > 1:
    i -= 1
    print('i - 1 = {0}'.format(i))
elif i < 1:
    print("i = {0} {1} {2}!".format(i, 'L', "O"))
    if i == 0:
        print("ZEEEEERO!")
else:
    print('I like single quotes for printing "double quotes".')
# tokens: identifiers, keywords, operators, delimiters, literals
# identifiers: start with A-Z,a-z,_ ; continue with digits 0-9 as well.
import keyword
print(len(keyword.kwlist), "keywords:", keyword.kwlist)

# list examples
l = [123, "Hello", 3.14]
len(l)
l[0]
l[1]
l[2]
print(l[0:2])
print(l[:2])
print(l[1:])
print(l[:-1])
help(l)
print(l + [3, 4, 5])
l.append("World")
print(l.pop(3))
print(l.pop())
values = [3, 1, 4, 1, 5]
values.sort()
print(values)
values.reverse()
print(values)

m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(m[2])
print(m[2][0])

# list comprehensions
col2 = [row[1] for row in m]
print(col2)
col2plus1 = [row[1] + 1 for row in m]
print(col2plus1)
mPlus1 = [[col + 1 for col in row] for row in m]
print(mPlus1)
mDiag = [m[i][i] for i in range(len(m))]
print(mDiag)
#m = [[1, 2, 3], [4, 5, 6]]
mTrans = [[m[c][r] for c in range(len(m))] for r in range(len(m[0]))]
print(mTrans)

# iterators/generators
g = (m[i][i] for i in range(len(m)))
print(next(g))
print(next(g))
print(next(g))
g = iter(range(2,4))
print(next(g))
print(next(g))

# map over list
print(sum([1, 2, 3]))
sums = [sum(row) for row in m]
print(sums)
print(list(map(sum, m)))

# sets
print({m[r][c] for c in range(len(m[0])) for r in range(len(m))})
evens = {i for i in range(0, 10) if i % 2 == 0}
print(evens)
print({ch for ch in "testing 1 2 3"})
print({ord(ch) for ch in "testing 1 2 3"})

# dictionaries
d = {ch : ord(ch) for ch in "testing 1 2 3"}
for key in d:
    print(key, "=>", d[key])
for key in sorted(d):
    print(key, "=>", d[key])
d = {}
d['num'] = 42
d['list'] = [1, 2, 3]
d['dict'] = {'a':1, 'b':2, 'c':3}
print(d)
d['num'] += 100;
d['list'].append(4)
d['dict']['d'] = 4
print(d)
if not 'foo' in d:
    print('bar')
print(d.get('foo', 'barnone'))
print(d.get('foo') if 'foo' in d else 'barnone') # same

# tuple - like a list, but immutable
t = (3, 1, 4)
help(t)

# files
f = open('test.txt', 'w')
f.write('testing ...\n')
for i in range(1, 4):
    f.write('{0}\n'.format(i))
f.close()
f = open('test.txt', 'r')
words = [word for line in f.readlines() for word in line.split()]
print(words)

# functions
def plusOne(n):
    return n + 1

print(list(map(plusOne, [0, 2, 4])))

# objects
class BankAccount:
    intRate = 0.01
    
    def __init__(self, name='none', amount=0):
        self.name = name
        self.amount = amount
        
    def deposit(self, amount):
        self.amount += amount

    def withdraw(self, amount):
        self.amount -= amount

    def __str__(self):
        return "BankAccount[name={0},amount={1}]".format(self.name, self.amount)

ba = BankAccount('Ann', 1000000)
print(ba)
ba.deposit(1)
print(ba)
ba.withdraw(1000000)
print(ba)
ba.foo = 'bar'
print(ba.foo)
print(BankAccount.intRate)
BankAccount.intRate = 0.02
print(BankAccount.intRate)











