- i know this... ?
echo "alias python=python3" >> ~/.bash_profile python --version
- ok
help()help(len)help(str)boolclass =>help(3 == 4)
exit()quit()- control-D
- 'Use spaces around operators, except for **, which should not be surrounded by spaces:'
print(8**3)
- comment with
#. - The block ends when you outdent back to the original level.
- You can also have multiple levels of indentation, though you should avoid using more than two levels.
- style guide for python AKA PEP 8.
- string literals:
return ("This is a long string. "
"It's actually very long. "
"It spans multiple lines. "
"Are you getting tired of this? "
"So am I.")
- fstrings (?!) and rstrings (?!) triple quoted strings (?!)
- (Then there's a bit about how to write various collections over multiple lines. This is straight-forward, but I have not yet learnt about these collections and how they work. They look similar to arrays, tuples and objects in other languages.)
- End collections with a comma, like javascript objects.
- use parentheses:
return (obj.bar1
+ obj.bar2
+ obj.bar3)
- use backslash to end a line you want to continue:
result = value1 + \
value2 + \
value3
- alternative REPLs
- don't know what to do with this: https://jupyter.org/try-jupyter/lab/
import platform
platform.python_version()
# '3.13.1'
- installed with
brew install jupyterlab
- Pdb module for later
- yup
- Everything with a value in Python is said to be an object. (so like Ruby)
- Python has more classes than most. Here are just some:
- integers
- floats
- boolean
- strings
- ranges
- tuples
- lists
- dictionaries
- sets
- frozen sets
- functions
- noneType ( some call this a primitive )
'Hello, world!' # str literal
3.141592 # float literal
True # bool literal
{'a': 1, 'b': 2} # dict literal
[1, 2, 3] # list literal
(4, 5, 6) # tuple literal
{7, 8, 9} # set literal
- not all objects have literal forms:
range(10) # Range of numbers: 0-9
range(1, 11) # Range of numbers: 1-10
set() # Empty set
frozenset([1, 2]) # Frozen set of values: 1 and 2
- skip
- skim
- In Python, booleans sometimes act like numeric values: you can use them in mathematical and comparison expressions. You shouldn't do that, really.
- skim
- strings of characters.
- There is one significant difference between a text sequence and an ordinary sequence. Ordinary sequences contain zero or more objects, but a text sequence does not contain any objects: it simply contains the characters (or bytes) that make up the text sequence. Those characters or bytes are not objects; they are simply part of the value.
'Hi there' # Single quotes
"Monty Python's Flying Circus" # Double quotes
# Triple single quotes
'''King Arthur: "What is your name?"
Black Knight: "None shall pass!"
King Arthur: "What is your quest?"
Black Knight: "I have no quarrel with you,
but I must cross this bridge."
'''
# Triple double quotes
"""Man: "Is this the right room for an argument?"
Other Man: "I've told you once."
Man: "No you haven't!"
"""
- triple quotes are often used for multi-line strings and a special kind of comment
print("C:\\Users\\Xyzzy") # Each \\ produces a literal \
my_str[1]
my_str[-3]
- string literals with an
rprefix are raw string literals.Raw string literals don't recognise escapes like/.
# Both of these print C:\Users\Xyzzy
print("C:\\Users\\Xyzzy") # Each \\ produces a literal \
print(r"C:\Users\Xyzzy") # raw string literal
- The same with
ffor formatted string literals. f strings enable string interpolation. - escape curly braces by doubling them:
foo = 'hello'
print(f'Use {{foo}} to embed a string: {foo}')
# Use {foo} to embed a string: hello
- Make numbers more readable with this:
print(f'{123456789:_}') # 123_456_789
print(f'{123456789:,}') # 123,456,789
- of function type
None-> the absence of value. MIssing, unset, unavailable data, sometimes an error.
- list literals use square brackets
- tuples use parentheses
- Lists are mutable, tuples are immutable.
- If you want to define a tuple with one element you must include a comma like this:
my_tuple = (1,)
print(type(my_tuple)) # <class 'tuple'>
>>> tuple(range(5))
(0, 1, 2, 3, 4)
>>> tuple(range(5, 10))
(5, 6, 7, 8, 9)
>>> list(range(1, 10, 2))
[1, 3, 5, 7, 9]
>>> list(range(0, -5, -1))
[0, -1, -2, -3, -4]
- unordered collections of objects
- This book just deals with dictionaries, which are like javascript objects.
my_dict = {
'dog': 'barks',
'wind': 'blows',
'fire': 'burns'
}
print(my_dict)
- The only significant requirement for keys is that they are hashable.
- unordered collections of unique objects. (the objects are sometimes called members)
d1 = {} # Empty dict
print(type(d1))
# <class 'dict'>
s1 = set() # Empty set
print(s1)
set()
# Create a set from a literal
s2 = {2, 3, 5, 7, 11, 13}
print(s2)
{2, 3, 5, 7, 11, 13}
# Create a set from a string
s3 = set("hello there!")
{'t', 'o', 'e', 'l', ' ', 'h', '!', 'r'}
- all correct
- 'True' => string
- False => Boolean
- (1, 2, 3) => Tuple
- 1.5 => float
- [1, 2, 3] List
- 2 => Integer
- rage(5) => range
- {1, 2, 3} => Set
- None => none
- {'foo': 'bar'} => dictionary.
-
yup
names = ('Asta', 'Butterscotch', 'Pudding', 'Neptune', 'Darwin')
pet = {
'Asta': 'dog',
'Butterscotch': 'cat',
'Pudding': 'cat',
'Neptune': 'fish',
'Darwin': 'lizard',
}
len()- 3 types:
- Built-in => available everywhere
- standard => needn't downlaod them but, but need to import them.
- non-standard => download them
/and//for Integer division? => rounds it.
print(16 // 3) # 5
print(16 // -3) # -6
print(16 // 2.3) # 6.0
print(-16 // 2.3) # -7.0
- there are slight imprecisons. 0.1 + 0.2 is not exaclty equal to 0.3.
- be preciser with this:
import math
math.isclose(0.1 + 0.2, 0.3) # True
- or this:
from decimal import Decimal
Decimal('0.1') + Decimal('0.2') == Decimal('0.3')
# True
==
- skim
- capitalsa re less than lower case in comparison
print(int('5')) # 5
print(float('3.141592')) # 3.141592
- Python implicitly coerces True to the integer value 1 and False to 0
print(type(1)) # <class 'int'>
print(type(3.14)) # <class 'float'>
print(type(True)) # <class 'bool'>
print(type('abc')) # <class 'str'>
print(type([1, 2, 3])) # <class 'list'>
print(type(None)) # <class 'NoneType'>
foo = 42 # Variables work, too
print(type(foo)) # <class 'int'>
print(type('abc').__name__) # str
print(type(False).__name__) # bool
print(type([]).__name__) # list
print(type('abc') is str) # True
print(type('abc') is int) # False
print(type(False) is bool) # True
print(type([]) is list) # True
print(type([]) is set) # False
- or
isinstancefunction when dealing with inheritance.
print(isinstance('abc', str)) # True
print(isinstance([], set)) # False
class A:
pass
class B(A):
pass
b = B()
print(type(b).__name__) # B
print(type(b) is B) # True
print(type(b) is A) # False (b's type is
# not A)
print(isinstance(b, B)) # True
print(isinstance(b, A)) # True (b is instance of A and B)
strrepr- ... i have not understood this
len()
print(len('Launch School')) # 13 (string)
print(len(range(5, 15))) # 10 (range)
print(len(range(5, 15, 3))) # 4 (range)
print(len(['a', 'b', 'c'])) # 3 (list)
print(len(('d', 'e', 'f', 'g'))) # 4 (tuple)
print(len({'foo': 42, 'bar': 7})) # 2 (dict)
print(len({'foo', 'bar', 'qux'})) # 3 (set)
- yep, nothing to see here.
- Unline javascript, trying to access a property on an object that does not exist will raise an Error:
print(my_dict['d']) # KeyError: 'd'
my_dict = {
'dog': 'barks',
'cat': 'meows',
'pig': 'oinks',
}
my_dict['pig'] = 'snorts'
print(my_dict)
# Pretty printed for clarity
# {
# 'dog': 'barks',
# 'cat': 'meows',
# 'pig': 'snorts'
# }
my_dict['fish'] = 'glub glub'
print(my_dict)
# Pretty printed for clarity
# {
# 'dog': 'barks',
# 'cat': 'meows',
# 'pig': 'snorts',
# 'fish': 'glub glub'
# }
-
An expression combines values, variables, operators, and calls to functions to produce a new object;
- Literals: 5, 'Karl', 3.141592, True, None
- Variable references: foo or name when these variables have been previously defined.
- Arithmetic operations: x + y or a * b - 5.
- Comparison operations: 'x' == 'x' or 'x' < 'y'.
- String operations: 'x' + 'y' or 'x' * 32.
- Function calls: print('Hello') or len('Python').
- Any valid combination of the above that evaluates to a single object.
-
A statement, on the other hand, is an instruction that tells Python to perform an action of some kind:
- Assignment: like x = 5. This doesn't evaluate as a value; it assigns a value to a variable.
- Control flow: such as if, else, while, for, and so on. These determine the flow of your program but don't evaluate as a value themselves.
- Function and class definitions: using def or class.
- Return statements: like return x, which tells a function to exit and return a value. return itself doesn't return a value; it informs the function what value it should return.
- Import statements: such as
import math.
-
Key differences:
- expressions always return a value, statements do not
- expressions are often parts of statements (in
y = x + 5x + 5is an expression) - Statements often represent bigger chuncks of functionality like loops or conditionals; expressions deal with determining values.
- precedence. But you should use parentheses to make it clear.
1
sandy = 'sandy'
rodger = 'rodger'
full_name = sandy + ' ' + rodger
print (full_name)
4936 - 4930int(((4936 % 49) - 6) / 10)(4936 // 100) - 404936 // 1000
510print(int('5') + int('10'))- yes - correct
- false
int('3.1415')=> valueError- true -> correct
defcreates functions- call a fucntion with
()
- snake_case
- constants -> SCREAMING_SNAKE_CASE
- class names -> PascalCase
-
it's just
+=etc. -
but you can smush together lists: q
bar = [1, 2, 3] # bar is [1, 2, 3]
bar += [4, 5] # + with lists appends
# bar is now [1, 2, 3, 4, 5]
print(bar) # prints [1, 2, 3, 4, 5]
- It talks about set union, but has not introduced this term:
bar |= {2, 3, 4, 5} # | performs set union
- nothing new
- index => idiomatic
- CatName => non-idiomatic
- lazy_dog => non-idiomatic WRONG -> idiomatic
- quick_Fox => non-idiomatic
- 1stCharacter => non-idiomatic WRONG illegal
- operand2 => non-idiomatic WRONG idiomatic
- BIG_NUMBER => non-idiomatic
- π => illegal WRONG non-idiomatic
- same as above
- index => non-idiomatic (all chars should be capitalised)
- CatName => non-idiomatic (all chars should be capitalised) snake_case => non-idiomatic (all chars should be capitalised) LAZY_DOG3 => idiomatic 1ST => illegal, should not begin with a digit operand2 => non-idiomatic (all chars should be capitalised) BIG_NUMBER => idiomatic Π => non-idiomatic, not an Ascii char
name = 'Victor'
print(f'Good Morning {name}')
print(f'Good Afternoon {name}')
print(f'Good Evening {name}')
age = 35
print(f'You are {age} years old.')
print(f'In 10 years, you will be {age + 10} years old.')
print(f'In 20 years, you will be {age + 20} years old.')
print(f'In 30 years, you will be {age + 30} years old.')
print(f'In 40 years, you will be {age + 40} years old.')
balance = 1000
interestRate = 1.05
balance *= interestRate
balance *= interestRate
balance *= interestRate
balance *= interestRate
balance *= interestRate
print(balance)
- already did it
obj = 42 # assignment
obj = 'ABcd' # reassignment
obj.upper() # neither CORRECT
obj = obj.lower() # reassign CORRECT
print(len(obj)) # neither CORRECT
obj = list(obj) # reassign CORRECT
obj.pop() # mutate CORRECT
obj[2] = 'X' # MUTATE
obj.sort() # MUTATE
set(obj) # neither
obj = tuple(obj) # REASSIGN
sepkeyword to seperate output:
print(1, 2, 3, 'a', 'b', sep=',') # 1,2,3,a,b
print('a', 'b', 'c', 'd', 'e', sep='') # abcde
- The end keyword argument defines what print() prints after it prints the last argument. By default, it prints a newline (\n).
print(1, 2, 'a', 'b', sep=',', end=' <-\n')
# 1,2,a,b <-
print('a', 'b', end='', sep=','); print('c', 'd', sep=',')
# a,bc,d
print("What's your name?")
name = input()
print(f'Good Morning, {name}!')
- or
name = input("What's your name? ")
print(f'Good Morning, {name}!')
name = input('what is your name? ')
print(f'Hello {name}')
age = input('give me your age ')
print(f'in 10 years you will be {int(age) + 10} years old')
def hello():
print('Hello')
return True
hello() # invoking function; ignore return value
print(hello()) # using return value in a `print` call
>>> print(print())
None => for some reason the return value is None ?
- about 70 of them
- Here are some:
- float
- int
- str, list, tuple
- set, frozenset
- input, print
- type
- len
- min/max
print(min(-10, 5, 12, 0, -20)) # -20
print(max(-10, 5, 12, 0, -20)) # 12
print(min('over', 'the', 'moon')) # 'moon'
print(max('over', 'the', 'moon')) # 'the'
print(max(-10, '5', '12', '0', -20))
# TypeError: '>' not supported between instances
# of 'str' and 'int'
- falsey:
- False, None
- all numeric 0 values (integers, floats, complex)
- empty strings: ''
- empty collections: [], (), {}, set(), frozenset(), and range(0)
- Custom data types can also define additional falsy value(s).
- truthy
- everything else
collection1 = [False, False, False]
collection2 = (False, True, False)
collection3 = {True, True, True}
print(any(collection1)) # False
print(any(collection2)) # True
print(any(collection3)) # True
print(any([])) # False
print(all(collection1)) # False
print(all(collection2)) # False
print(all(collection3)) # True
print(all([])) # True
- a comprehension ? like the following
numbers = [2, 5, 8, 10, 13]
print([number % 2 == 0 for number in numbers])
# [True False True True False]
- interning
- use a comprehension to limit the output to just the names that don't contain
__:
>>> names = sorted(dir(range(1)))
>>> names = [name for name in names
... if '__' not in name]
>>> print(names)
['count', 'index', 'start', 'step', 'stop']
def say():
"""
The say function prints "Hi!"
"""
print('Hi!')
print('-' * 60)
print(say.__doc__)
print('-' * 60)
help(say)
- all familiar from Javascript, except this:
def scope_test():
if True:
foo = 'Hello'
else:
bar = 'Goodbye'
print(foo)
print(bar)
scope_test()
- order of look-up for an identifier:
- local namespace
- enclosing namespace
- global namespace
- built-in namespace
- defaults to
None
- yup
- you should say methods when discussing functions explicitly designed to require calling objects.
- yup
- undefined variable foo
- bar
def multiply():
arg1 = float(input('Enter the first number: '))
arg2 = float(input('Enter the second number: '))
return arg1 * arg2
print(multiply())
- nothin'
- nothin' at all
- print 'hello', retunr an error -> nope, just return an error, unline JS
- too many args also throws an error:
def foo(bar, qux):
print(bar)
print(qux)
foo(42, 3.141592, 2.718)
- yep
- yep
- yep
- yep
- yep
- yep
def remainders_3(numbers):
return [number % 3 for number in numbers]
numbers_1 = [0, 1, 2, 3, 4, 5, 6]
numbers_2 = [1, 2, 4, 5]
numbers_3 = [0, 3, 6]
numbers_4 = []
print(any(remainders_3(numbers_1)))
print(any(remainders_3(numbers_2)))
print(any(remainders_3(numbers_3)))
print(any(remainders_3(numbers_4)))
- yep
def remainders_5(numbers):
return [number % 5 for number in numbers]
numbers_1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers_2 = [1, 2, 3, 4, 6, 7, 8, 9]
numbers_3 = [0, 5, 10]
numbers_4 = []
print(all(remainders_5(numbers_1)))
print(all(remainders_5(numbers_2)))
print(all(remainders_5(numbers_3)))
print(all(remainders_5(numbers_4)))
- new ones:
andornotelifinstead ofelsif.
pass: add a comment for clarity.
value = int(input('Enter a number: '))
if value > 10:
print('value is greater than 10')
elif value < 10:
print('value is less than 10')
else:
pass # we don't care about 10 itself
==operands have equal values- Sometimes
==will equate operands of different types, sometimes not:
print(5 == float(5)) # True
big_num = 12345678901234567
print(float(big_num) == big_num) # False
- so like
!in js ?- `print(not True) # False
&&/||
- short circuit evaluation
- Falsey:
FalseNone0''- all empty collections
- custom data types can be falsey
- The final value returned by an expression using
andororis the final value read by the phrase:
print(3 and 'foo') # foo
print('foo' or 3) # foo
print([] or 3) # 3
is_ok = bool(foo or bar)
- this is the list:
==,!=,<=,<,>,>=-> comparisonnotandor
- it's switch syntax
value = 'box'
match value:
case 5:
print('value is 5')
case 6:
print ('value is 6')
case _:
print('value is neither 5 nor 6')
value1 if condition else value2print("Triangle" if shape.sides() == 3 else "Square")
# 1.
False or (True and False) # False
True or (1 + 2) # True
(1 + 2) or True # 3
True and (1 + 2) # True WRONG -> 3
False and (1 + 2) # False
(1 + 2) and True # True
(32 * 4) >= 129 # False
False != (not True) # False
True == 4 # False
False == (847 == '847') # True
# 2.
def even_or_odd(n):
if (n % 2 == 1):
print('odd')
else:
print('even')
# 3.
# product2
# product3 NOPE -> product not found
# print(142 == '142') # False
# 4.
def foo():
return True
def qux():
return 1
def baz():
if (foo()):
return 'bar'
else:
return qux()
# 5.
def is_list_empty(my_list):
if my_list:
print('Not Empty')
else:
print('Empty')
# is_list_empty([]) # Empty
# 6.
def capitalise_long_words(word):
if len(word) > 10:
return word.upper()
else:
return word
# print(capitalise_long_words('bar'))
# print(capitalise_long_words('barnabussyl'))
# 7.
def number_range(n):
if n < 0:
print(f'{n} is less than 0')
elif n <= 50:
print(f'{n} is between 0 and 50')
elif n < 100:
print(f'{n} is between 51 and 100')
else:
print(f'{n} is greater than 100')
number_range(0) # 0 is between 0 and 50
number_range(25) # 25 is between 0 and 50
number_range(50) # 50 is between 0 and 50
number_range(75) # 75 is between 51 and 100
number_range(100) # 100 is between 51 and 100
number_range(101) # 101 is greater than 100
number_range(-1) # -1 is less than 0
- python has a lot
- 3 main categories:
- sequences
- ranges
- tuples (tuples are just frozen lists)
- lists
- strings as text sequences, although simultaneously strings are not collections since the characters inside are not objects. This seems to be a contradiction, but I do not have the time to pin down the precise nature of the truth now.
- mappings
- dictionaries
- sets
- sets
- frozen sets
- sequences
- collections of elements with an integer index value -> so analogous to JS arrays)
- "heterogeneous" -> composed of parts of different kinds. (Unlike ranges which are homogeneous -> they always contain integers)
- Strings are text sequences
- unordered collection
letters = {'a', 'b', 'c'}
letters.add('d')
print(letters)
# {'a', 'b', 'c', 'd'} (order may differ)
frozen_letters = frozenset(letters)
frozen_letters.add('e')
# AttributeError: 'frozenset' object has no
# attribute 'add'
- python will ignore any attempt to add duplicate members to a set:
letters = {'a', 'b', 'c', 'b', 'a'}
print(letters)
# {'a', 'c', 'b'} (order may differ)
letters.add('c')
print(letters)
# {'a', 'c', 'b'} (order may differ)
- Since Python 3.7 sets of integers appear to be ordered, but this is an illusion, easy to trick and not to be relied upon:
numbers = { 1, 2, 37, 4, 5 }
print(numbers) # {1, 2, 4, 37, 5}
- types tha maintain an unordered collection of k/v pairs. (so JS objects?)
- There's a few, but this book only looks at
dicttypes. - Keys must be unique.
- Keys must be hashable values (usually immutable)
- since Python 3.7 order is preserved, but you should think of them as unordered.
str()=>''str(something)
str() # returns '' (empty string)
str('abc') # returns 'abc'
str(42) # returns '42'
str(3.141592) # returns '3.141592'
str(False) # returns 'False'
str(None) # returns 'None'
str(range(3, 7)) # returns 'range(3, 7)'
str([1, 2, 3]) # returns '[1, 2, 3]'
str(int) # returns "<class 'int'>"
str(list) # returns "<class 'list'>"
class Person: pass
str(Person())
# returns "<__main__.Person object at 0x1006d21e0>"
range(start, stop, step)
r = range(5, 12, 2)
print(list(r)) # [5, 7, 9, 11]
r = range(12, 8, -1)
print(list(r)) # [12, 11, 10, 9]
r = range(12, 5, -2)
print(list(r)) # [12, 10, 8, 6]
- empty ranges are often bugs:
r = range(5, 5, 1)
print(list(r)) # []
r = range(5, 7, -1)
print(list(r)) # []
range(start, stop)
- defaults to 1 step
range(stop
-
start defaults to
0 -
so
range(5)is the same asrange(0, 5, 1) -
ranges are "lazy sequences"
- without argument they create an empty collection:
list()tuple()set()frozenset()
- args must be iterables
my_str = 'Python'
my_list = list(my_str)
print(my_list) # ['P', 'y', 't', 'h', 'o', 'n']
my_tuple = tuple(my_list)
print(my_tuple) # ('P', 'y', 't', 'h', 'o', 'n')
my_set = set(my_tuple)
print(my_set) # {'t', 'o', 'n', 'h', 'P', 'y'}
- one can use these constructors to duplicate a collection:
my_list = [5, 12, 2]
another_list = list(my_list)
print(my_list) # [5, 12, 2]
print(another_list) # [5, 12, 2]
print(my_list == another_list) # True
print(my_list is another_list) # False
# so `is` is like === in JS, right?
- This demonstrates that copying nested lists results in shallow copies being copied:
my_list = [[1, 2, 3], [4, 5, 6]]
another_list = list(my_list)
print(my_list) # [[1, 2, 3], [4, 5, 6]]
print(another_list) # [[1, 2, 3], [4, 5, 6]]
print(my_list == another_list) # True
print(my_list is another_list) # False
print(my_list[0] is another_list[0]) # True
print(my_list[1] is another_list[1]) # True
# 2.
stuff = ('hello', 'world', 'bye', 'now')
# LS1
stuff = ('hello', 'world', 'goodbye', 'now')
# LS2
stuff = stuff[0:2] + ('goodbye', stuff[3])
# LS3
stuff = stuff[0:2] + ('goodbye', stuff[3])
# 3
# Similarities
# both tuples and lists have number indexes
# both heterogenous
# 4
# 5
# 6
pi = 3.141592
str_pi = str(pi)
# 7
range(7) # 0, 1, 2, 3, 4, 5, 6. correct
range(1, 6) # 1, 2, 3, 4, 5 correct
range(3, 15, 4) # 3, 7, 11
range(3, 8, -1) # []
range(8, 3, -1) # 8, 7, 6, 5, 4
# 8
# print(range(3, 17, 4)) # => range(3, 17, 4)
result = tuple(range(3, 17, 4))
# print(result) # => (3, 7, 11, 15)
# since ranges are lazy sequences you have to convert the range to a non-lazy sequence
# 9.
# 1 -> yes they are equal
# 2 -> no they are not the same object
# 3 -> yes the nested lists are equal
# 4 -> Yes they are the same object because they copy did not create a new nested list, it only created a reference to the first nested list. This is the nature of shallow copies, they only copy down one level (as it were)
# 10
# no it will jumble them up. Sets by definition are unordered collections
names = { 'Chris', 'Clare', 'Karis', 'Karl',
'Max', 'Nick', 'Victor' }
# print(names)
# 11
# use a dict:
countries = {
'Alice': 'USA',
'Francois': 'Canada',
'Inti': 'Peru',
'Monika': 'Germany',
'Sanyu': 'Uganda',
'Yoshitaka': 'Japan',
}
print(countries['Alice'])
- nothing new here.
string = 'abcdefghi'
print(string[3:7]) # defg
print(string[-6:-2]) # defg
print(string[2:8:2]) # ceg
print(repr(string[3:3])) # ''
print(string[:]) # abcdefghi
print(string[::-1]) # ihgfedcba
seq = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(seq[3:7]) # [4, 5, 6, 7]
print(seq[-6:-2]) # [5, 6, 7, 8]
print(seq[2:8:2]) # [3, 5, 7]
print(seq[3:3]) # []
print(seq[:]) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(seq[::-1]) # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
seq = [[1, 2], [3, 4]]
seq_dup = seq[:]
print(seq[0] is seq_dup[0]) # True
- dict keys must be immutable
- ie
inandnot in
seq = [4, 'abcdef', (True, False, None)]
print(4 in seq) # True
print(4 not in seq) # False
print('abcdef' in seq) # True
print('abcdef' not in seq) # False
print('cde' in seq[1]) # True
print('cde' not in seq[1]) # False
print('acde' in seq[1]) # False
print('acde' not in seq[1]) # True
print((True, False, None) in seq) # True
print((True, False, None) not in seq) # False
print(3.14 in seq) # False
print(3.15 not in seq) # True
- can't use min max with heterogenous collections:
my_set = {1, 4, '-9', 16, '25', -36, -63, -1}
min(my_set)
# TypeError: '<' not supported between instances of 'str' and 'int'
max(my_set)
# TypeError: '>' not supported between instances of 'str' and 'int'
nums = (1, 2, 3, 4, 5)
print(sum(nums))
- which just means using
.index('value')to return an index.- (if you do it with a string it tells you where that string begins)
- and
.count(number)to count how many occurences in a list.
names = ['Karl', 'Grace', 'Clare', 'Victor',
'Antonina', 'Allison', 'Trevor']
print(names.index('Clare')) # 2
print(names.index('Trevor')) # 6
print(names.index('Chris'))
# ValueError: 'Chris' is not in list
numbers = [1, 3, 6, 5, 4, 10, 1, 5, 4, 4, 5, 4]
print(numbers.count(1)) # 2
print(numbers.count(3)) # 1
print(numbers.count(4)) # 4
print(numbers.count(7)) # 0
- zip
iterable1 = [1, 2, 3]
iterable2 = ('Kim', 'Leslie', 'Bertie')
iterable3 = [None, True, False]
zipped_iterables = zip(iterable1, iterable2, iterable3)
print(list(zipped_iterables))
# Pretty printed for clarity
# [
# (1, 'Kim', None),
# (2, 'Leslie', True),
# (3, 'Bertie', False)
# ]
zipped_iterables = zip(iterable1, iterable2, strict=True)
- iterators can only be consumed once!
dict.keys
dict.values
dict.items
appendinsertandextendseq.append
- remove
- pop
- clear
sorteddoesn't mutate the list,list.sortdoes.
names = ('Grace', 'Clare', 'Allison', 'Trevor')
print(sorted(names))
# ['Allison', 'Clare', 'Grace', 'Trevor']
print(names)
# ('Grace', 'Clare', 'Allison', 'Trevor')
names = list(names)
print(names)
# ['Grace', 'Clare', 'Allison', 'Trevor']
print(names.sort()) # None
print(names)
# ['Allison', 'Clare', 'Grace', 'Trevor']
- sort string numbers like this:
numbers = ['1', '5', '100', '15', '534', '53']
numbers.sort()
print(numbers) # ['1', '100', '15', '5', '53', '534']
numbers.sort(key=int)
print(numbers) # ['1', '5', '15', '53', '100', '534']
str.capitalizestr.titlecapwords:
import string
print(string.capwords("i can't believe it's already mid-july."))
# I Can't Believe It's Already Mid-july.
swapcase
str.isalpha- str.isdigit()
- str.isalnum()
- str.islower()
- str.isupper()
- str.isspace()
text.isalpha() and text.isascii()to exclude non ASCII letters
- str.strip
- with
repr
text = ' \t abc def \n\r'
print(repr(text)) # ' \t abc def \n\r'
print(repr(text.strip())) # 'abc def'
split:
text = ' Four score and seven years ago. '
print(text.split())
# ['Four', 'score', 'and', 'seven', 'years', 'ago.']
print('no-spaces'.split()) # ['no-spaces']
- str.find and str.rfind
- you can't nest mutable collections inside some collections. For instance, you can't nest a mutable collection such as a list, dictionary, or another set inside a set:
>>> my_set = {1, 2, 3, [4, 5]}
TypeError: unhashable type: 'list'
>>> my_set = {1, 2, 3, {4, 5}}
TypeError: unhashable type: 'set'
print([2, 3] == [2, 3]) # True
print([2, 3] == [3, 2]) # False (diff sequence)
print([2, 3] == [2]) # False (diff lengths)
print([2, 3] == (2, 3)) # False (diff types)
print({2, 3} == {3, 2}) # True (same members)
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 2, 'a': 1}
dict3 = {'a': 1, 'b': 2, 'c': 3}
print(dict1 == dict2) # True (same pairs)
print(dict1 == dict3) # False
- done
forandwhile
names = ['Chris', 'Max', 'Karis', 'Victor']
upper_names = []
index = 0
while index < len(names):
upper_name = names[index].upper()
upper_names.append(upper_name)
index += 1
print(upper_names)
# ['CHRIS', 'MAX', 'KARIS', 'VICTOR']
names = ['Chris', 'Max', 'Karis', 'Victor']
upper_names = []
for name in names:
upper_name = name.upper()
upper_names.append(upper_name)
print(upper_names)
# ['CHRIS', 'MAX', 'KARIS', 'VICTOR']
# Looping over a set
my_set = {1000, 2000, 3000, 4000, 5000}
for member in my_set:
print(member)
-continue and break
names = ['Chris', 'Max', 'Karis', 'Victor']
upper_names = []
for name in names:
if name == 'Max':
continue
upper_name = name.upper()
upper_names.append(upper_name)
print(upper_names);
# ['CHRIS', 'KARIS', 'VICTOR']
for value in collection:
if not some_condition():
continue
# some code here
if not another_condition():
continue
# some more code here
numbers = [3, 1, 5, 9, 2, 6, 4, 7]
found_item = -1
index = 0
while index < len(numbers):
if numbers[index] == 5:
found_item = index
break
index += 1
print(found_item)
- use
zip
- 3 types
- list
- dict
- set
- the most common.
[ expression for element in iterable if condition ]is the format
squares = [ number * number for number in range(5) ]
print(squares) # [0, 1, 4, 9, 16]
squares = { f'{number}-squared': number * number
for number in range(1, 6) }
print(squares)
# pretty-printed for clarity.
{
'1-squared': 1,
'2-squared': 4,
'3-squared': 9,
'4-squared': 16,
'5-squared': 25
}
squares = { number * number for number in range(1, 6) }
print(squares) # {1, 4, 9, 16, 25}
- it would be something called a "generator expression" for some reason.
# 1. because it doesn't increment
# 2.
# age = int(input('How old are you? '))
# print(f'You are {age} years old.')
# print()
# for future in range(10, 50, 10):
# print(f'In {future} years, you will be {age + future} years old.')
# 3.
# my_list = [6, 3, 0, 11, 20, 4, 17]
# index = 0
# while index < len(my_list):
# print(my_list[index])
# index += 1
# 4.
# my_list = [6, 3, 0, 11, 20, 4, 17]
# index = 0
# while index < len(my_list):
# if (my_list[index] % 2 == 0):
# print(my_list[index])
# index += 1
# for n in my_list:
# if (n % 2 == 1):
# print(n)
# 5.
my_list = [
[1, 3, 6, 11],
[4, 2, 4],
[9, 17, 16, 0],
]
# for list in my_list:
# for n in list:
# if (n % 2 == 0):
# print(n)
#6
new_list = []
my_list = [
1, 3, 6, 11,
4, 2, 4, 9,
17, 16, 0,
]
for n in my_list:
if (n % 2 == 1):
new_list.append('odd')
else:
new_list.append('even')
# print(new_list)
# 7
def find_integers(tuple):
return [ elem
for elem in tuple
if type(elem) is int ]
my_tuple = (1, 'a', '1', 3, [7], 3.1415,
-4, None, {1, 2, 3}, False)
integers = find_integers(my_tuple)
# print(integers)
# 8
# Write a comprehension that creates a dict object whose keys are strings and whose values are the length of the corresponding key. Only keys with odd lengths should be in the dict. Use the set given by my_set as the source of strings.
my_set = {
'Fluffy',
'Butterscotch',
'Pudding',
'Cheddar',
'Cocoa',
}
name_lengths = { name: len(name) for name in my_set
if (len(name)) % 2 == 1}
# print(name_lengths)
# 9
def factorial(n):
if (n == 1):
return n
else:
return n * factorial(n-1)
# print(factorial(1)) # 1
# print(factorial(2)) # 2
# print(factorial(3)) # 6
# print(factorial(4)) # 24
# print(factorial(5)) # 120
# print(factorial(6)) # 720
# print(factorial(7)) # 5040
# print(factorial(8)) # 40320
# print(factorial(25)) # 15511210043330985984000000
# 10
import random
highest = 10
while True:
number = random.randrange(highest + 1)
# print(number)
if number == highest:
break
# 11.
index = 0
while (index < len(my_list)):
if (my_list[index] % 2 == 0):
print(my_list[index])
index += 1
- nothing new here.
- I'm tired and not a lot of this is going in, but I'm assuming that most of it is the same as Javascript
# 1
# the == is asking whether the 2 comparees have equal value.
# the is statement is asking whether the two variables are pointing to he same object in memory.
# 2
set1 = {42, 'Monty Python', ('a', 'b', 'c')}
set2 = set1
set1.add(range(5, 10))
print(set2)
# this will print the two objects added together
# 3 will print an error because dict2 is a shallow copy, so Monty Python doesn't exist on dict1 -ok I misread the question, but I got the concept right.
# 4 the original dict 1 object values -> no
# You may modify this line
# import copy
dict1 = {
'a': [[7, 1], ['aa', 'aaa']],
'b': ([3, 2], ['bb', 'bbb']),
}
# dict2 = copy.deepcopy(dict1) # You may modify the `???` part
# of this line
# All of these should print False
# print(dict1 is dict2)
# print(dict1['a'] is dict2['a'])
# print(dict1['a'][0] is dict2['a'][0])
# print(dict1['a'][1] is dict2['a'][1])
# print(dict1['b'] is dict2['b'])
# print(dict1['b'][0] is dict2['b'][0])
# print(dict1['b'][1] is dict2['b'][1])
# 6
dict1 = {
'a': [{7, 1}, ['aa', 'aaa']],
'b': ({3, 2}, ['bb', 'bbb']),
}
dict2 = dict(dict1) # You may modify the `???` part
# of this line
print(dict1 is dict2) # false
print(dict1['a'] is dict2['a']) # true
print(dict1['a'][0] is dict2['a'][0]) # true
print(dict1['a'][1] is dict2['a'][1]) # true
print(dict1['b'] is dict2['b']) # true
print(dict1['b'][0] is dict2['b'][0]) # true
print(dict1['b'][1] is dict2['b'][1]) # true
- composing function calls, AKA composition => passing around functions as arguments.
- Many methods simply return None. Thus, chaining in Python isn't very common.
- pyPI
pipcommand to download.- Every python file is/can be a module
import math
print(math.sqrt(math.pi)) # 1.7724538509055159
- or more targetedly:
from math import pi, sqrt
print(sqrt(pi)) # 1.7724538509055159
- "Be aware, though, that from circumvents the naming conflict benefits of import." ?
- aliases can be useful:
import math as m
print(m.sqrt(m.pi)) # 1.7724538509055159
import math
print(math.sqrt(36)) # 6.0
print(math.sqrt(2)) # 1.4142135623730951
from datetime import datetime as dt
date = dt.strptime("July 16, 2022", "%B %d, %Y")
weekday_name = date.strftime('%A')
print(weekday_name) # Saturday
-... skim
- This code shows hoisting is not a thing in Python:
top()
def top():
bottom()
def bottom():
print('Reached the bottom')
- The only rule of thumb is that you should define all your functions before you try to invoke the first one
def foo():
def bar():
print('BAR')
bar() # BAR
foo()
bar() # NameError: name 'bar' is not defined
- No matter how deeply nested we are, the global statement stipulates that the listed identifiers are to be interpreted as global variables; that is, as identifiers in the global namespace.
- unlike with the global statement, the nonlocal statement requires the named variable to already exist.
- The global and nonlocal statements often reflect poor design choices that can be implemented more clearly
# 1: CHRIS -> correct
# 2
import math
# print(math.sqrt(37)) # 6.082762530298219
import math as m
# print(m.sqrt(37)) # 6.082762530298219
from math import sqrt
# print(sqrt(37)) # 6.082762530298219
# 3
def sum_of_squares(num1, num2):
def square(n):
return n * n
return square(num1) + square(num2)
# print(sum_of_squares(3, 4)) # 25 (3 * 3 + 4 * 4)
# print(sum_of_squares(5, 12)) # 169 (5 * 5 + 12 * 12)
# 4
# counter = 0
# def increment_counter():
# global counter
# counter += 1
# print(counter) # 0
# increment_counter()
# print(counter) # 1
# increment_counter()
# print(counter) # 2
# counter = 100
# increment_counter()
# print(counter) # 101
# 5
def all_actions():
counter = 0
def increment_counter():
nonlocal counter
counter += 1
print(counter) # 0
increment_counter()
print(counter) # 1
increment_counter()
print(counter) # 2
counter = 100
increment_counter()
print(counter) # 101
all_actions()