Python Language Intro (Part 1)

Agenda

  1. Language overview
  2. White space sensitivity
  3. Basic Types and Operations
  4. Statements & Control Structures
  5. Functions
  6. OOP (Classes, Methods, etc.)
  7. Immutable Sequence Types (Strings, Ranges, Tuples)
  8. Mutable data structures: Lists, Sets, Dictionaries

1. Language overview

Note: this is not a language course! Though I'll cover the important bits of the language (and standard library) that are relevant to class material, I expect you to master the language on your own time.

Python ...

  • is interpreted
  • is dynamically-typed (vs. statically typed)
  • is automatically memory-managed
  • supports procedural, object-oriented, imperative and functional programming paradigms
  • is designed (mostly) by one man: Guido van Rossum (aka “benevolent dictator”), and therefore has a fairly opinionated design
  • has a single reference implementation (CPython)
  • version 3 (the most recent version) is not backwards-compatible with version 2, though the latter is still widely used
  • has an interesting programming philosophy: "There should be one — and preferably only one — obvious way to do it." (a.k.a. the "Pythonic" way) — see The Zen of Python
In [2]:
# by default, only the result of the last expression in a cell is displayed after evaluation.
# the following forces display of *all* self-standing expressions in a cell.

from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

2. White Space Sensitivity

Python has no beginning/end block markers! Blocks must be correctly indented (4 spaces is the convention) to delineate them.

In [2]:
if False:
    print('In if-clause')
else:
    print('In else-clause')
In else-clause
In [3]:
for x in range(5):
    print('In for loop body')
In for loop body
In for loop body
In for loop body
In for loop body
In for loop body
In [5]:
def foo():
    print('In function definition')

foo()
In function definition

3. Basic Types and Operations

In Python, variables do not have types. Values have types (though they are not explicitly declared). A variable can be assigned different types of values over its lifetime.

In [16]:
a = 2 # starts out an integer
print(type(a)) # the `type` function tells us the type of a value

a = 1.5
print(type(a))

a = 'hello'
print(type(a))

a

print(a,x)
<class 'int'>
<class 'float'>
<class 'str'>
Out[16]:
'hello'
hello 4

Note that all the types reported are classes. I.e., even types we are accustomed to thinking of as "primitives" (e.g., integers in Java) are actually instances of classes. All values in Python are objects!

There is no dichotomy between "primitive" and "reference" types in Python. All variables in Python store references to objects.

Numbers

In [13]:
# int: integers, unlimited precision
1
500
-123456789
6598293784982739874982734
x=4
x
Out[13]:
1
Out[13]:
500
Out[13]:
-123456789
Out[13]:
6598293784982739874982734
Out[13]:
4
In [17]:
# basic operations
1 + 2
1 - 2
2 * 3
2 * 3 + 2 * 4
2 / 5
2 ** 3 # exponentiation
abs(-25)
Out[17]:
3
Out[17]:
-1
Out[17]:
6
Out[17]:
14
Out[17]:
0.4
Out[17]:
8
Out[17]:
25
In [18]:
# modulus (remainder) and integer division
10 % 3
10 // 3
Out[18]:
1
Out[18]:
3
In [19]:
# floating point is based on the IEEE double-precision standard (limit to precision!)
2.5
-3.14159265358924352345
1.000000000000000000000001
Out[19]:
2.5
Out[19]:
-3.1415926535892433
Out[19]:
1.0
In [20]:
# mixed arithmetic "widens" ints to floats
3 * 2.5
1 / 0.3
Out[20]:
7.5
Out[20]:
3.3333333333333335

Booleans

In [21]:
True
False
Out[21]:
True
Out[21]:
False
In [22]:
not True
Out[22]:
False
In [23]:
True and True
False and True
True and False
False and False
Out[23]:
True
Out[23]:
False
Out[23]:
False
Out[23]:
False
In [24]:
True or True
False or True
True or False
False or False
Out[24]:
True
Out[24]:
True
Out[24]:
True
Out[24]:
False
In [31]:
# relational operators
1 == 1
1 != 2
1 < 2
1 <= 1
1 > 0
1 >= 1
1.0 == 1
1.0000000000000000001 == 1
type(1) == type(1.0)
1.000000000000001 == 1
Out[31]:
True
Out[31]:
True
Out[31]:
True
Out[31]:
True
Out[31]:
True
Out[31]:
True
Out[31]:
True
Out[31]:
True
Out[31]:
False
Out[31]:
False
In [29]:
# object identity (reference) testing
x = 1000
y = 1000
x == x
x is x
x is not x
Out[29]:
True
Out[29]:
True
Out[29]:
False
In [32]:
x == y
x is y
x is not y
Out[32]:
True
Out[32]:
False
Out[32]:
True
In [33]:
# but Python caches small integers! so ...
x = 5
y = 5
x == y
x is y
Out[33]:
True
Out[33]:
True
In [41]:
for i in range(5):
    i
Out[41]:
0
Out[41]:
1
Out[41]:
2
Out[41]:
3
Out[41]:
4

Strings

In [34]:
# whatever strings you want
'hello world!'
"hello world!"
Out[34]:
'hello world!'
Out[34]:
'hello world!'
In [36]:
# convenient for strings with quotes:
print('she said, "how are you?"','x')
print("that's right!")
she said, "how are you?" x
that's right!
In [37]:
'hello' + ' ' + 'world'
'thinking... ' * 3
'*' * 80
Out[37]:
'hello world'
Out[37]:
'thinking... thinking... thinking... '
Out[37]:
'********************************************************************************'

Strings are an example of a sequence type; https://docs.python.org/3.5/library/stdtypes.html#typesseq

Other sequence types are: ranges, tuples (both also immutable), and lists (mutable).

All immutable sequences support the common sequence operations, and mutable sequences additionally support the mutable sequence operations

In [3]:
# indexing
greeting = 'hello there'
greeting[0]
greeting[6]
len(greeting)
greeting[len(greeting)-1]
Out[3]:
'h'
Out[3]:
't'
Out[3]:
11
Out[3]:
'e'
In [5]:
# negative indexes
greeting[-1]
greeting[-2]
greeting[-len(greeting)]
Out[5]:
'e'
Out[5]:
'r'
Out[5]:
'h'
In [4]:
# "slices"
greeting[0:11]
greeting[0:5]
greeting[6:11]
Out[4]:
'hello there'
Out[4]:
'hello'
Out[4]:
'there'
In [6]:
# default slice ranges
greeting[:11]
greeting[6:]
greeting[:]
Out[6]:
'hello there'
Out[6]:
'there'
Out[6]:
'hello there'
In [7]:
# slice "steps"
greeting[::2]
greeting[::3]
greeting[6:11:2]
Out[7]:
'hlotee'
Out[7]:
'hltr'
Out[7]:
'tee'
In [8]:
# negative steps
greeting[::-1]
Out[8]:
'ereht olleh'
In [9]:
greeting
greeting[0]="m"
Out[9]:
'hello there'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-9-6eebfb5e51af> in <module>()
      1 greeting
----> 2 greeting[0]="m"

TypeError: 'str' object does not support item assignment
In [12]:
# other sequence ops
greeting="Tello there"
greeting.count('e')
greeting.index('e')
greeting.index('e', 2)
'e' in greeting
'z' not in greeting
min(greeting)
max(greeting)
Out[12]:
3
Out[12]:
1
Out[12]:
8
Out[12]:
True
Out[12]:
True
Out[12]:
' '
Out[12]:
't'
In [19]:
"matthew"[5:8]
Out[19]:
'ew'
In [11]:
for i in greeting:
    print(i)
h
e
l
l
o
 
t
h
e
r
e
In [15]:
range(1,10,.5)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-15-83e7be853e59> in <module>()
----> 1 range(1,10,.5)

TypeError: 'float' object cannot be interpreted as an integer

Strings also support a large number of type-specific methods.

Type "Conversions"

Constructors for most built-in types exist that create values of those types from other types:

In [16]:
# making ints
int('123')
int(12.5)
int(True)

# floats
float('123.123')

# strings
str(123)
Out[16]:
123
Out[16]:
12
Out[16]:
1
Out[16]:
123.123
Out[16]:
'123'

Operators/Functions as syntactic sugar for special methods

In [20]:
5 + 6
(5).__add__(6)
Out[20]:
11
Out[20]:
11
In [21]:
class MyInt(int):
    def __add__(self, other):
        return self * other
In [22]:
a = MyInt(5)
b = MyInt(6)
a + b
Out[22]:
30
In [23]:
abs(-2.8)
(-2.8).__abs__()
Out[23]:
2.8
Out[23]:
2.8
In [24]:
'hello' + ' ' + 'world'
'hello'.__add__(' ').__add__('world')
Out[24]:
'hello world'
Out[24]:
'hello world'

None

None is like "null" in other languages

In [25]:
# often use as a default, initial, or "sentinel" value

x = None

note: notebooks do not display the result of expressions that evaluate to None

In [26]:
None
In [27]:
a = None
b = 100
c = None
a
b
c
Out[27]:
100

some functions return None, so when we call them, there is no "Out" cell

In [28]:
print('Hello')
Hello

"Truthiness"

All objects in Python can be evaluated in a Boolean context (e.g., as the condition for an if statement). Values for most types act as True, but some act (conveniently, usually) as False.

In [40]:
if None: # try numbers, strings, other values here
    print('tests as True')
else:
    print('tests as False')
tests as False

What tests as False?