Tells Python you are going to pass it a string containing Python code.
e.g. python -c “import this”
Python Scripting
Run a python script at startup
edit /etc/rc.local
“and add a command to execute your script between the commented section and exit 0. Something like:
python3 /home/pi/foo.py&
The ampersand at the end will run the script as a background process, which will allow all the other services of the Pi to continue booting up.”
Make a python script into an exectuable
py2exe
PyInstaller
Make a python script able to be run like other BASH scripts (without python3 command)
Add shebang line to top of script
#!/usr/bin/env python3
this searches at runtime for your environment
you could specify the path to your python but it's a little more portable this way, although the first way isn't fullproof
Make your script executable
chmod +x my_script.py
You still need to run the script with ./my_script.py because otherwise the shell automatically searches for the program in the PATH variable in which it won’t be able to find your script unless you put it there manually.
systemctl restart allowed without password due to that command being added to the /etc/sudoers.d/ directory
Make a given BASH command that normally requires a sudo password not require a password ^Linux
Access command line arguments in Python
- sys.argv
- import sys print("This is the name of the script: ", sys.argv[0]) print("Number of arguments: ", len(sys.argv)) print("The arguments are: " , str(sys.argv))
- via bash: python sysargv.py arg1 arg2
This is the name of the script: sysargv.py Number of arguments in: 3 The
arguments are: ['sysargv.py', 'arg1', 'arg2']
- argv[0] is always the name of your script
- argv[1] is the first argument, etc.
- the python command is not included
- argv short for argument vector
- vector short for list
Execute a Python Command inline from the BASH shell
python -c 'print("Hello World!")'
Launch a program from Python
- Example
from datetime import datetime from time import sleep import subprocess
for count in range(0, 60): filename = str(datetime.now()) + ".jpg"
subprocess.call(["fswebcam", filename]) sleep(60)” Excerpt From: Matt
Richardson and Shawn Wallace. “Getting Started with Raspberry Pi.” Maker
Media, Inc., 2016-07-15. iBooks.
- “This is a simple time-lapse script that will snap a photo from a webcam once a minute for an hour.”
- subprocess.call
- “The subprocess.call function takes a list of strings, concatenates them together (with spaces between), and attempts to execute the program specified. If it is a valid program, the Raspberry Pi will spawn a separate process for it, which will run alongside the Python script. The command in the preceding example is the same as if you typed the following at a terminal prompt:
- fswebcam 20160812.jpg
- To add more parameters to the program invocation, just add strings to the list in the subprocess.call function:
- subprocess.call(["fswebcam", "-r", "1280x720", filename])”
Alias python3 to python
add alias python='python3' at the end of .bash_profile
So, locally, you'd set an environment variable with `export DJANGO_SECRET_KEY=SECRET_KEY` then you'd get it with `os.getenv(DJANGO_SECRET_KEY)` furthermore, you can get fun. Say, you want to set lots of things in the environment, and you want to put them in a dict... ```prefixes = ["DJANGO_"] {k: v for k, v in os.environ.items() for prefix in prefixes if k.startswith(prefix)}```
Python auto adds return None to end of every defined function that doesn't have a return statement
basically makes the function evaluate to something from within the function as opposed to just printing it or something so that you can use it with other things more directly and usefully.
All functions return a value. If no return keyword is used the value returned is None as in the print() function. Similar to how loops implicitly add the continue statement at the end of the loop.
e.g., can assign a function to a variable to give that variable the value returned from the function.
Whenever the function executes a return statement, the function is immediately exited and statements after it won’t be executed.
You could use return (with no value) to exit the function at that specific point.
Required Parameters
Def f(parameter1, parameter2):
Determined merely by their position in the function
Keyword Parameters (aka optional parameters)
Determined by the = sign
def function(keyword = 0, keyword2 = 2):
Both are optional. If the keyword arguments are specified in the function call, that value overwrites the value given in the function definition. Otherwise, the value defaults to 0 and 2 (as specified in the function definition).
You can combine positionally determined required/default arguments and keyword arguments, but the keyword arguments must come last.
Stub a Function
- pass
- when you don't want to fill out a function or class yet - python will just not evaluate the function I guess.
e.g. def temp_function(): pass
Main Function?
Similar to Java functionality, some Python programs have a main function they use as their main loop/execution.
if __name__ == '__main__': main()^Environment
Docstrings
Named as such because it documents your code and can be used to generate documentation or be accessed at runtime for info on that function.
LC: "If the first thing after the function header is a string (some tools insist that it must be a triple-quoted string), it is called a docstring and gets special treatment in Python and in some of the programming tools. One way to retrieve the information in this string is to use the interactive interpreter, and enter the expression .__doc__, which will retrieve the docstring for the function. So the string you write as documentation at the start of a function is retrievable by Python tools at runtime. This is different from comments in your code, which are completely eliminated when the program is parsed. By convention, Python programmers use docstrings for the key documentation of their functions."
1st line: Clearly explain what function does.
Next lines: list parameters, data types, etc. then what exactly it returns
Types of Functions
Helper Function
Mutator Function
mutates or changes the internal state of the object.
Decorators #issue
Lambda Functions
Technically expressions I think, since they evaluate down to an expression?
Aka an anonymous function, since they are not named
can take any number of arguments, but can only have one expression.
lambda arguments : expression
x = lambda a : a + 10 print(x(5))
LC: "Functions that return values are sometimes called fruitful functions. In many other languages, a chunk that doesn’t return a value is called a procedure, but we will stick here with the Python way of simply calling it a function, or if we want to stress its lack of a return value, a non-fruitful function."
However, technically, the return value is None when you don't have a return statement
The return value is the "fruit".
You can either use temporary values and then return the temp value or evaluate something right after the return value.
term "lifetime" is the time when the function is being executed
LC: "Although the bad_square function works, it is poorly written. We have done it here to illustrate an important rule about how variables are looked up in Python. First, Python looks at the variables that are defined as local variables in the function. We call this the local scope. If the variable name is not found in the local scope, then Python looks at the global variables, or global scope. This is exactly the case illustrated in the code above. While power is not found locally in bad_square, it does exist globally and therefore can be used in the function. But the appropriate way to write this function would be to pass power as an argument to the square function. For practice, you should rewrite the bad_squareexample to have a second parameter called power."
Term: "shadows" - when a local variable has the same name as a global variable
In general, local variables should not have the same name as any global variables.
Functions can belong to a class
Composition (of functions) Calling one function from within the body of another, or using the return value of one function as an argument to the call of another.
Object-Oriented Python
Objects
“Pretty much everything that isn’t a keyword can be considered an object. An object is a combination of data and behaviors that has a name. You can change an object’s data, retrieve information from it, and even manipulate other objects. ... In Python, strings, lists, functions, modules, and even numbers are objects. A Python object can be thought of as an encapsulated collection of attributes and methods. You get access to these attributes and methods using a simple dot syntax”
values, integers, etc.
A compound data type that is often used to model a thing or concept in the real world. It bundles together data (attributes) and operations on that data (methods).
The terms instance and object are used interchangeably.
Objects are ?always? a member of a class?
State
things that the object knows about itself
The Object Class
Type Class?
Classes
Create a Class
x, y point example
class Point: """ Point class for representing and manipulating x,y coordinates. """ def __init__(self): """ Create a new point at the origin """ self.x = 0 self.y = 0
Instantiation
some_variable = SomeClass()
"The combined process of “make me a new object” and “get its settings initialized to the factory default settings” via the __init__ method is called instantiation."
Instances
An object that belongs to a class. The terms instance and object are used interchangeably.
Technically you can create a new object with the same variable and the existing object doesn't go away.
The self Keyword
- Needs self as the first parameter.
- "The self parameter (you could choose any other name, but nobody ever does!) is automatically set to reference the newly-created object that needs to be initialized."
- The self param is simply the place that the object goes to when you instantiate it or reference it. The object itself gets automatically passed to the class and it goes to the self param.
- self parameter allows function to call other functions? And also to use variables. #issue
def find_food(self): self.move()
- I think 1) the self. part is needed since you don't know the name of the object you will initialize. And 2) the (self) is simply the standard way parameters in functions are setup, so it's kind of a formal structure and clues you in to what you should expect - that the (self) parameter will get filled in with the value/argument which would be the name of the variable used to initialize the object (say, evan_object) and then that value is able to be used inside that function (in the definition of the function inside the definition of the class) wherever and exactly where the word 'self' is used - ie self.move() - evaluated as evan_object.move().
Attributes
aka fields or ?properties? in other languages
Variables in a class are called attrbiutes
Instance Attributes
(variables)
Instance Attributes
owned by the instance
Class Attributes/Static Attributes
Just define them outside of a method
Class Attributes
owned by the class itself
shared by all instances of the class
usually placed at top of class definition right below header
accessed same way instance attributes are
General Example
class Shark: animal_type = "fish"
Static Attributes
Delete an object's attribute
del someObject.the_answer
Constants? Final like Java?
Methods
- Instance Methods
- Getter & Setter Methods
- Properties?
- Class Methods & Static Methods
- Magic Methods/Dunder Methods
- aka special methods in Java
- Inhertied from the Object parent class that all classes inherits from.
- Just add that method in your class named the same. You don't normally need to anything extra
- __init__ Methods (aka constructors in other languages)
- Initializer Method
- __init__
- aka "init method" or "constructor method"
- __init__ function is a special function in python classes that can only have this name
- if you have this function in a class, every object of that class that gets initialized has this function run at initialization.
- A way to add ?'properties'? (attributes, variables?) to every member of that class automatically.
- e.g.
class Giraffes: def init(self, spots): self.giraffe_spots = spots
ozwald = Giraffes(100) gertrude = Giraffes(150)
print(ozwald.giraffe_spots) print(gertrude.giraffe_spots) 100 150
- first we created an instance of the Giraffes class (ozwals), using a parameter value of 100 - this calls the __init__ function and using 100 for the value of the spots parameter. Same for gertrude but with 150.
- Every class automatically uses the name of the class as the name of the constructor function.
- __repr__
- __add__
- When Python evaluates an expression with an addition operator, it calls the method __add__ on the first operand object, passes the second operand object into __add__ as a parameter, and returns the result.
- Method Overrides
- Override a Method
- use same name of method, but can use your own code
- def noise(self): if self.angry(): # an angry Tiger says GRRRR! return "GRRRR!" else: # a non-angry Tiger behaves like a Cat return Cat.noise(self)
- Override an __init__() Method
- super().__init__( [args] )
- newer, preferred way because it automatically calls all superclasses' __init__ methods and in order.
- Deprecated/Old Way:
- This way can't automatically invoke all superclasses' __init__ methods like the above method can.
- class HouseCat(Cat): def __init__(self, name): # first, initialize as a normal Cat Cat.__init__(self) # then set the name attribute self.name = name
- first, used the superclass' __init__ method and then used its own __init__ method
- Classes can have functions in them (by just adding them indented inside the class) that its instances can then use as methods on values/objects
- Methods are essentially functions you call on values.
- A function that is defined inside a class definition and is invoked on instances of that class.
- functions that allow you to change its state or ask questions about its state. Methods are like the actions that an object is able to do, or the questions that an object is able to answer about itself.
- Static method?
- class Hello(object): @staticmethod def main(args): print("Hello, World")
Access Control (Private and Public)
Python does not have a builtin concept of private and public like Java. You can modify any attribute and field.
static annotation? method?
_underscore_methods indicate that they are to be treated as private and not messed with/not guaranteed to not change and thus could break your code if you alter them
Inheritance
super keyword?
If any new attributes or methods have the same name as an attribute or method in our parent class, it is used instead of the parent one.
Don't use () when a class is the most super class or doesn't use inheritance. It's ok not to use () but it might be a good practice to stick to since you can deduce that the class is not doing inheritance.
Subclass
Superclass
Parent Class
Child Class
Create a subclass of an imported module's class
import turtle class StarTurtle(turtle.Turtle): def star(self, numpoints, radius): for i in range(0, numpoints): self.forward(radius) self.back(radius) self.left(360 / numpoints)
Call a method in another class:
Cat.noise(self)
vs some_instance.noise() if you wanted noise() from the instance's class. Since self doesn't line up correctly outside its own class, you need to specify the class you want the method from and then pass the self variable as a parameter so it gets passed correctly in that class.
Polymorphism
e.g. print() can print strings, objects, integers, etc.
e.g. square.draw() and circle.draw() use the same interface/method to draw itself, even though the underlying code is pretty different. You wouldn't need to know which class a given reference is - you can just call .draw() on it and you know it will work.
Abstract methods and classes?
Data Classes
Python 3.7
A class can also be thought of as a template, or blueprint, for the objects that are instances of it. It contains both the attributes and the methods that each instance of it will have.
"It may be helpful to think of a class as a factory for making objects. The class itself isn’t an instance of a point, but it contains the machinery to make point instances. Every time you call the constructor, you’re asking the factory to make you a new object. As the object goes through the production line, its initialization method is executed in order to get the object properly set up with its factory default settings."
Classes are capitalized, actually camelCase.
General Example:
- class Cat: def __init__(self): # every Cat comes into this world tired and hungry self.tired = True self.hungry = True def sleep(self): self.tired = False # a Cat always wakes up hungry self.hungry = True def eat(self): if self.hungry: self.hungry = False else: # eating when already full makes a Cat sleepy self.tired = True def noise(self): # sleepy cats say prrrr, energized cats say meow! if self.tired: return "prrrr" else: return "meow!" class Tiger(Cat): # notice the (Cat) in parentheses def angry(self): # a Tiger is angry whenever it is both hungry and tired return self.tired and self.hungry def noise(self): if self.angry(): # an angry Tiger says GRRRR! return "GRRRR!" else: # a non-angry Tiger behaves like a Cat return Cat.noise(self) def main(): hobbes = Tiger() print("hobbes says:", hobbes.noise()) hobbes.sleep() print("After sleeping, hobbes says:", hobbes.noise()) hobbes.eat() print("After eating, hobbes still says:", hobbes.noise()) hobbes.eat() print("After eating again, hobbes says:", hobbes.noise()) if __name__ == "__main__": main()
hobbes says: GRRRR! After sleeping, hobbes says: meow! After eating,
hobbes still says: meow! After eating again, hobbes says: prrrr
Copying Classes Example
- From Python for Kids:
- What value is being printed?
- car1 = Car() car1.wheels = 4 car2 = car1 car2.wheels = 3 print(car1.wheels) car3 = copy.copy(car1) car3.wheels = 6 print(car1.wheels)
- Answer:
car1 = Car() car1.wheels = 4 car2 = car1 car2.wheels = 3
print(car1.wheels) >>> 3 Why is the result of the print
statement 3, when we clearly set 4 wheels for car1 on line 2? Because at
line 3, both variables car1 and car2 are pointing at the same object.
Now, what about the second print statement? car3 = copy.copy(car1)
car3.wheels = 6 print(car1.wheels) >>> 3 In this case, car3 is
a copy of the object; it’s not labeling the same object as car1 and
car2. So when we set the number of wheels to 6, it has no effect on
car1’s wheels.
Converting an Object to a String
print(someObject) returns <__main__.SomeClass object> unless there is a __repr__ or __str__ method defined in the object's class
In other words, you as the programmer get to choose what a someObject object should look like when it gets printed.
It is required that the __repr__ method create and return a string.
__str__
does essentially the same thing as the __repr__ method.
the print function would invoke the __str__ method. Technically, this is the first thing it tries to do, and then it falls back on invoking the __repr__ method.
the str() type converter function will use whatever __str__ method we provide. We have "overridden" the str()s method functionality for that class.
Returning a List as a String
When trying to return a string from a list in a class via __str__ or __repr__ methods, if the elements in the list are objects from another class, those elements need to be returned via the __repr__ method in that class. If the elements in the list use the __str__ method, the list elements will return <__main__.ClassName object>. I think this is due to how the str() function works on lists - if you want it to apply to each item, str() uses __repr__ to do so, not __str__. The other class that returns the list itself can be either __repr__ or __str__
Python has a powerful feature that allows a designer of a class to decide what an operation like == or < should mean. E.g., sometimes the class creator will attach shallow equality semantics, and sometimes deep equality.
__add__():
changes what the + operator does
Special Methods
aka magic methods or dunder methods
__someSpecialMethod__
dunder naming for special methods in classes
e.g.
__init__
__repr__
__str__
__add__
@property
#issue
You can assign instances to a dictionary
# Then, create some instances of classes in the dictionary: dictionary["DoubleSquare 1"] = DoubleSquare(5) dictionary["long rectangle"] = Shape(600,45) #You can now use them like a normal class: print(dictionary["long rectangle"].area()) dictionary["DoubleSquare 1"].authorName("The Gingerbread Man") print(dictionary["DoubleSquare 1"].author)
Each class can use any functions inside it, but also any functions inside any of its parents (or grandparents, great-grandparents, etc.)
class Things:
Note capital letter
top level class (no parents)
has child (below - Inanimate class)
class Inanimate(Things):
child of Things class
class Animate(Things):
also child of Things class
class Animals(Animate):
child of Animate class
jerry = Animals()
creates object in Animals class & assigns it to variable jerry
This is an 'instance' of the class Animals, but sometimes just called an 'object' of the Animals class or a 'member' of the class
avery = turtle.Pen()
creates an object or instance of the Pen class that is provided by the turtle module. So it is basically providing the 'full path' to where the class is located?
Composition
models the "has a" relationship by storing an object as a variable in another object.
E.g. Inside a Dog class, storing an owner instance of a Person class in the owner attribute: self.owner = owner
From the self-taught programmer: "In Python classes are objects. ... Each class in Python is an object that is an instance of class "type"
From the self-taught programmer: "Every class in Python inherits from a parent class called Object."
Can import your own functions from other programs
Can assign functions to a variable and functions can be arguments to other functions
Python Reference
Variables
Variables refer to objects
foo = 20
Variable Names
One word
Letters, numbers, _
Can’t begin with a number
Case sensitive
Python convention is to start variable names with a lower case letter
Multiple Assignment Trick
cats = [bob, bill, harry,] a, b, c = cats
a, b, c = 1, 2, 3
Variable Swapping
a, b, = b, a
Constants
Python doesn't have constants, but you can just make a variable and not change it. It would't be safe/immutable obviously. Convention is still all caps – NAME_OF_CONSTANT = "Constant value"
Scope
Global and local variables & parameters, scope, etc.
“Parameters and variables that are assigned in a called function are
said to exist in that function’s local scope. Variables that are
assigned outside all functions are said to exist in the global scope. A
variable that exists in a local scope is called a local variable, while
a variable that exists in the global scope is called a global variable.
A variable must be one or the other; it cannot be both local and
global.”
“Think of a scope as a container for variables. When a scope is
destroyed, all the values stored in the scope’s variables are forgotten.
There is only one global scope, and it is created when your program
begins. When your program terminates, the global scope is destroyed, and
all its variables are forgotten.”
“A local scope is created whenever a function is called. Any variables
assigned in this function exist within the local scope. When the
function returns, the local scope is destroyed, and these variables are
forgotten. The next time you call this function, the local variables
will not remember the values stored in them from the last time the
function was called.”
“The reason Python has different scopes instead of just making
everything a global variable is so that when variables are modified by
the code in a particular call to a function, the function interacts with
the rest of the program only through its parameters and the return
value. This narrows down the list code lines that may be causing a bug.
If your program contained nothing but global variables and had a bug
because of a variable being set to a bad value, then it would be hard to
track down where this bad value was set. It could have been set from
anywhere in the program—and your program could be hundreds or thousands
of lines long! But if the bug is because of a local variable with a bad
value, you know that only the code in that one function could have set
it incorrectly.
While using global variables in small programs is fine, it is a bad
habit to rely on global variables as your programs get larger and
larger.” -Al Sweigart
A scope is like a container for variables. Or namespace.
Python: Local means local to a function or a class. Not ifs, loops, etc. But also inside a with block?
Variables (and parameters) assigned in a called function exist in the local scope.
Variables (and parameters) assigned outside all functions exist in the global scope.
Can only be local or global, not both.
There is only one global scope - it is created when your program begins and is destroyed when your program terminates, along with all its variable values.
Local scopes are created whenever a function is called. When the function returns all its variable values are lost and not remembered next time the function is called.
Scopes Matter
Code in the global scope cannot use any local variables.
However, a local scope can access global variables.
Code in a function’s local scope cannot use variables in any other local scope.
You can use the same name for different variables if they are in different scopes. That is, there can be a local variable named spam and a global variable also named spam.
Scopes exist to create some sanity in understanding and debugging via encapsulation of variables and functions and the possible ways they interact with other functions and objects in the program. Limiting them to simpler, direct input parameters to functions and return values and limiting the use of global variables in general is considered best practice? Also you can use functions whose source code you may have no idea how it works but you can still use it fine if you just know how to input its parameters and what you want returned - treating functions as black boxes which is common and perfectly ok.
There can be more than one local scope at the same time, e.g., when a function calls another function, but the nested function’s scope is still destroyed when it returns to the outside scope.
But, as a rule, in order to make things easier to understand, you should avoid using different variables with the same name in different scopes. Just use unique names.
Using Global Variables in a Local Scope
In a function's local scope, unless there is a parameter or assigned variable with the same name, you can read a global variable from a local scope without needing to use global.
But if you need to modify a global variable from within a function, since you need to use the assignment operator which defaults to local in a function, you would need to use global. I think you just need to use global once since it is defining it for that whole local scope from then on.
4 Rules to Tell Whether a Variable is in a Local or Global Scope
If a variable is being used in the global scope (that is, outside of all functions), then it is always a global variable.
If there is a global statement for that variable in a function, it is a global variable.
Otherwise, if the variable is used in an assignment statement in the function, it is a local variable.
But if the variable is not used in an assignment statement, it is a global variable.
In a function, there is no way to use a local variable named eggs and then later in the same function use the global variable eggs.
Global and Local Scope Example from ATBS
def spam(): print(eggs) # error eggs = 'spam local'
eggs = 'global' spam() Error = Local variable referenced before
assignment
- Python sees that there is an assignment statement for eggs in the spam() function first and therefore considers eggs to be local. But because print(eggs) is executed before eggs is assigned anything the local variable doesn't exist. Python will not fall back to using the global eggs variable.
Identity & Equality
Identity Comparison Operators v
Identity/Reference Equality
The two objects point to/refer to the same location in memory.
i.e. they refer to the same, identical, object.
E.g., changing a field/property in one object, changes it in both references (because it refers to the same object).
Equality/Value Equality
Two different objects, based on your equals() method implementation, have equal values.
String Equality & Immutability
Since strings are immutable, Python optimizes resources by making two names that refer to the same string value refer to the same object. (like the tentacle analogy for variables)
e.g.: string1 ='abc' string2 ='abc' string1 == string2 # returns True string1 is string2 # also returns True
Contra lists
2 Lists with the same values/elements are not the same object because the list is an object above the elements of the list. Each element of the list might be the same instances, but the lists would still be different. That is, if 2 lists have the same element values they would == each other, but they would not be the same object (is)
e.g.: a = [1, 2, 3] b = [1, 2, 3] a == b # returns True a is b # returns False
Here, they are different objects (is), but they == each other because these lists are evaluated via 'deep equality'
Shallow Equality & Deep Equality?
Shallow equality only compares the references, not the contents of the objects.
?"Equality of references, or two references that point to the same object."?
Deep equality compares the values “deep” in the object, not just the reference to the object.
"Equality of values, i.e., two references that point to objects that have the same value."
If two variables refer to the same object, they have both shallow and deep equality.
For example:
list1 == list2 checks deep equality (will check if their values are equal and return True if they are, even if they are independent objects (even if list1 is not list 2).
But with 2 instances of a class, a == b normally would check shallow equality and return False since they are 2 different references, even if they had the same internal values inside each instance
Shallow Copy & Deep Copy
copy.copy() & copy.deepcopy()
import copy
copy.copy()
shallow copy
copy.deepcopy()
deep copy
normally a variable given a list value is just a reference to the list. So if you have 2 variables that refer to that same list, changing the list via one list, changes it in the other variable since it is the same list by 2 different names.
?So a copy of a variable with a list value operates in this same way - changing one, changes both. This is called a shadow copy?
?deepcopy() when you want to?
Aliasing
- Since variables refer to objects, if we assign one variable to another, both variables refer to the same object
- e.g.
- a = [81, 82, 83] b = a print(a is b)
True
- Because the same list has two different names, a and b, we say that it is aliased. Changes made with one alias affect the other.
- b[0] = 5
- would change index [0] on both lists
- "Although this behavior can be useful, it is sometimes unexpected or undesirable. In general, it is safer to avoid aliasing when you are working with mutable objects. Of course, for immutable objects, there’s no problem; they can’t be updated or changed. That’s why Python is free to alias strings and integers when it sees an opportunity to economize."
Cloning
a = [1, 2, 3] b = a[:] # or b = list(a)
2 independent, separate instances of a list - it was cloned and has the same values after the clone but you are free to edit each list independently because they are not linked in anyway after the clone.
"So if we don’t want to alias the list, we need another option. If we want to modify a list and also keep the original list intact and unchanged, we need to be able to make a copy of the list itself, not just the reference. This process is sometimes called cloning, to avoid the ambiguity of the word copy. The easiest way to clone a list is to use the slice operator. Taking any slice of a creates a new list. In this case the slice happens to consist of the whole list."
hex()
id()
Will typically return the same id value for the same object, but apparently there are rare cases when it is not synonymous with is.
e.g. a is b to test if a and b refer to the same object or if they refer to 2 different instances of the value
x is y implies x == y, but x == y does not imply that x is y
Example Challenge from Python for Kids
Ch. 10, p. 144 Solution:
car1 = Car() u>>> car1.wheels = 4 v>>> car2 =
car1 car2.wheels = 3 print(car1.wheels) 3 Why is the result of the
print statement 3, when we clearly set 4 wheels for car1 at (1)?
Because at (2), both variables car1 and car2 are pointing at the
same object. Now, what about the second print statement?
car3 = copy.copy(car1) car3.wheels = 6 print(car1.wheels) 3 In
this case, car3 is a copy of the object; it’s not labeling the
same object as car1 and car2. So when we set the number of wheels
to 6, it has no effect on car1’s wheels.
_
A variable that stores the last expression
>>> 10 10 >>> _ 10 >>> _ * 3 30 >>> _ * 20 600
Python Data Types
Numbers
int
whole number
int()
Changes a data type to an integer
float
decimal
float()
Floating Point Inaccuracy
many scenarios
One way to accept approximate equality:
abs(a**2 + b**2 - c**2) < 0.001
Instead of a ** 2 + b ** 2 == c ** 2 (Pythagorean Theorem) this will result in true if it is within .001
complex
real and imaginary
Math & Science v
Dividing whole numbers in Python 3 does automatically convert to a float even if both are whole numbers
Python 2
int
whole number
long
bigger whole numbers
float
decimals
complex
real and imaginary
Narrow vs wide types
int is narrower than float, float narrower than complex, etc. because you can “fit” narrow types into wider ones
When doing operations among different type widths the rule of thumb is that Python converts the narrower type to the wider type and then does the operation
Dividing whole numbers returns the quotient without the remainder - it doesn’t automatically convert to float or anything, unlike Python3
Collections v
Boolean
bool
Best practice to name Boolean variables as is_variable_name to highlight it as a boolean variable
“Truthy” and “Falsey” Values
When used in conditions, 0, 0.0, and ‘’ (the empty string) evaluate to Boolean False and all other values in those data types evaluate to True.
So you could check if the user inputted anything for example so it would be True if so, and False if nothing was inputted. They're not exactly Boolean but they work. But best practice is to be more explicit and clear.
int(True)
1
int(False)
0
float(True)
1.0
float(False)
0.0
Trivial and non-trivial values
Are boolean True if non-trivial, False if trivial
Boolean Functions
common to give boolean functions names that sound like yes/no questions - e.g., is_divisible
can make the function more concise by taking advantage of the fact that the condition of the ifstatement is itself a boolean expression. We can return it directly, avoiding the if statement altogether: def is_divisible(x, y): return x % y == 0
It might be tempting to write something like if is_divisible(x, y) == True: but the extra comparison is not necessary.
Helps make code very expressive and readable
True
False
Boolean Short Circuiting
True and False are case-sensitive
bool()
returns the boolean value of the argument
Common Mistake:
num == 5 or 6 or 7, it will not be correct. The or operator must join the results of three equality checks. The correct way to write this is num == 5 or num == 6 or num == 7
Might be possible now? with chaining?
a = 5 to assign
a == b to compare as boolean
Strings are always != ints and floats etc as in 42 and '42', but floats can be equal to ints as in 42.0 == 42
NoneType
None
Normally represents the absence of a value
e.g. the return value of print() etc.
Similar to null in other languages
Boolean false
What’s returned when a function doesn’t return anything else
either from no return statement
or return alone
Type Casting
int(stringvariable)
str()
float()
print(float("123.45"))
Python usually automatically converts an int to a float when trying to combine an int and a float, but will truncate a float (19.99 becomes 19) if Python thinks a float should be an int for some reason. "truncation towards zero"
Every value in Python has exactly one datatype. Since everything is an object in Python programming, data types are actually classes and variables are instances (object) of these classes.
Mutability & Immutability
Object Checking (isinstance(), type(), __eq__, __ne__) v
Abstract Data Types
Composite Data Types
Type Annotations
?aka type hints?
Way to manually do type checking a la static-typed languages
Helps avoid commenting a la "Clean Code" conventions by using type annotations instead of a comment
Helps autocompletion because IDE will know what to suggest better
Strings are very similar to lists so you can use a lot of the same methods on them like len() , can be used in for loops, in and not in, have indexes and can be sliced and can be concatenated and replicated.
“ or ‘ or “”” or ‘’’
Alternate between them to avoid syntax errors if you need an apostrophe, quote, double quote, etc. 'This "is" cool' or "That 'is' cool" or "Evan's car"
Multiline string (triple string)
use triple “”” or '''
aka 'multiline string' which can be used for strings, e.g. to include line breaks
Escapes both ' and " and allows you to include line breaks (which aren't allowed normally) being able to do multiline strings since multiline strings include the newline character which needs to be handled correctly.
R String
r'some string'
aka 'raw string literal'
a backslash, \, is taken as meaning "just a backslash" (except when it comes right before a quote that would otherwise terminate the literal). That is, no "escape sequences" to represent newlines, tabs, backspaces, form-feeds, and so on. In normal string literals, each backslash must be doubled up to avoid being taken as the start of an escape sequence.
Helps with Regex, e.g.
the syntax of regular expression patterns is heavy with backslashes (but never at the end, so the "except" clause above doesn't matter) and it looks a bit better when you avoid doubling up each of them
Python does not have a separate character type. Just use strings with one character in it.
a string is a substring of itself, and the empty string is a substring of any other string.
- print('' in 'apple')
True
str()
Changes a number to a string
Ordered
Indexed with bracket notation
Strings are immutable
- The idiomatic way to modify a string is to create a new variable:
name = 'zophie a cat' newname = name[0:7] + 'the' + name[8:12]
Strings are list-like
So you can use list methods like slicing, indexing, iterating, len(), etc.
A bad index in Python, e.g. s[100] for the string "Hello", is a runtime error. However, slices work differently. If an index number in a slice is out of bounds, it is ignored and the slice uses the start or end of the string.
String Methods
- Capitalization
- .upper() & .lower()
- Returns a string in all uppercase or lowercase
- .isupper() & .islower()
- .capitalize()
- capitalizes the string (the first word of the string. Not the first word of every sentence.)
- .title()
- capitalizes every word in the string
- .istitle()
- isX String Methods
- isalpha()
- only letters and not blank
- isalnum()
- only letters and numbers and not blank
- isdecimal()
- only numeric characters and not blank
- isdigit()
- integers
- '5.0'.isdigit()
False
- isspace()
- only spaces, tabs, and newlines and is not blank
- Stripping (trim)
- .strip()
- strips whitespace from beginning and end of string (but not new lines, etc.?)
- .rstrip()
- 'right strip'
- Strips white spaces, newlines, ?tabs? from end of string
- .lstrip()
- 'left strip'
- Strips white spaces, newlines, ?tabs? from end of string
- .replace()
- replace a certain character with another
- .replace(old, new, count)
- count: how many times you want to replace that old occurrence with the new string
- .find
- Returns the leftmost index where the substring item is found
- .rfind()
- Returns the rightmost index where the substring item is found
- .rindex()
- Like rfind except causes a runtime error if item is not found
- index() also works, but rindex() only works on strings
- .startswith() & .endswith()
String Formatting
- F Strings (Newest, Best Style
- Python 3.6
- https://realpython.com/python-f-strings/
- "string interpolation"
- Newest, best way
- Faster than .format() and %-formatting
- an f-string is really an expression evaluated at run time, not a constant value.
- Can put any and all Python expressions in {}
- Like this way best since you can use existing variables right in the string itself which is better for readability/semantic reasons.
- similar to JavaScript’s Template Literals added in ES2015
- General Example
- name = "Eric" age = 74 f"Hello, {name}. You are {age}."
'Hello, Eric. You are 74.'
- Expressions
- a = 5 b = 10 f'Five plus ten is {a + b} and not {2 * (a + b)}.'
'Five plus ten is 15 and not 30.'
- Functions
- import math radius = 10 def area_of_circle(radius): return 2 * math.pi * radius f'Area of a circle with radius {radius}:{area_of_circle(radius)}'
'Area of a circle with radius 10:62.83185307179586'
- Methods
- f"{name.lower()} is funny."
'eric idle is funny.'
- Instances
- class Comedian: def __init__(self, first_name, last_name, age): self.first_name = first_name self.last_name = last_name self.age = age def __str__(self): return f"{self.first_name} {self.last_name} is {self.age}." def __repr__(self): return f"{self.first_name} {self.last_name} is {self.age}. Surprise!" new_comedian = Comedian("Eric", "Idle", "74") print(f"{new_comedian}")
'Eric Idle is 74.'
- Multiline
- With Parentheses
- name = "Eric" profession = "comedian" affiliation = "Monty Python" message = ( f"Hi {name}. " f"You are a {profession}. " f"You were in {affiliation}." )
'Hi Eric. You are a comedian. You were in Monty Python.'
- Need an f in front of each line
- With \ Character
- message = f"Hi {name}. " \ f"You are a {profession}. " \ f"You were in {affiliation}."
'Hi Eric. You are a comedian. You were in Monty Python.'
- Quotation Marks
- f"{'Eric Idle'}"
'Eric Idle'
- f'{"Eric Idle"}'
'Eric Idle'
- f"""Eric Idle"""
'Eric Idle'
- f'''Eric Idle'''
'Eric Idle'
- Dictionaries
- Just make sure to use different quotation marks around the f string than the ones you use to indicate the dictionary key.
- f"The comedian is {comedian['name']}, aged {comedian['age']}."
- Braces
- Double them up
- f"{{74}}"
'{ 74 }'
- Triple braces still only gives you one printed pair, but you just add more than 3 if you want more
- f"{{{{74}}}}"
'{{74}}'
- .format() (New Style)
- .format()
- introduced with Python3 but back-ported to 2.7
- Not set up to be able to name variables in the string itself contra to F strings which can name the variable right in the string which I like better for semantic/readability reasons.
- General Example
- "{} of {} was rad. He invented stickers in {}.".format(name, place, invention)
- Reference Whole List
- "{} of {} was rad. He invented stickers in {}.".format(*list_name)
- Reference Multiple Lists
- names = ["Conan", "Belit", "Valeria"] ages = [25, 21, 22] "{0[0]} is {1[0]} years old. Whereas {0[1]} is {1[1]} years old.".format(names, ages)
Conan is 25 years old. Whereas Belit is 21 years old.
- Named Arguments/Variables
- "{x}, {y}".format(x=5, y=12)
- Use Variables in {}
- As a kind of hack to reference existing variables by name in the string itself, if x and y are existing variables:
- x = 'abc' y = 'def' "{x}, {y}".format(x=x, y=y)
- Use variables with indexes:
- person = {'name': 'Eric', 'age': 74} "Hello, {name}. You are {age}.".format(name=person['name'], age=person['age'])
'Hello, Eric. You are 74.'
- Dictionary Trick
- person = {'name': 'Eric', 'age': 74} "Hello, {name}. You are {age}.".format(**person)
'Hello, Eric. You are 74.'
- Manual Order
- 'Here {1} is. Just {0} down the street.'.format(a, b)
- Instead of a first, then b, it's reversed
- Expressions Evaluated in ()
- "I have {} hens and {} roosters, for a total of {}.format(num_hens, num_roosters, num_hens + num_roosters)
- I don't think you can put the expression in the {}
- %-formatting (Old Style)
- Don't use. Deemphasized, but not deprecated and apparently will be around for a very long time. Some still prefer it, its similar to C, and maybe faster in some cases? Also the cause of a lot of common errors. Doesn't work exactly right with tuples and dictionaries.
- print('Week %s = %s' % (week, coins))
- Padding Numbers
- print('{:4d}'.format(42))
42
- print('{:04d}'.format(42))
0042
- Cut off decimals past a certain point?
String Concatenation
string1 + string2
"Hello world" + "!" * 10
Hello world!!!!!!!!!!
Escaping Characters, Special Characters, & Unicode
\"
(Invisible characters)
Space
New Line Character
\n
If you evaluate a string that contains a newline character you will see the character represented as \n. If you print a string that contains a newline you will not see the \n, you will just see its effects.
String Comparison
- 'someString' == 'otherString'
- 'apple' < 'zebra'
True
- 'apple' < 'Zebra'
False
- "Dog" < "Doghouse"
True
- "dog" < "Doghouse"
False
- The length does not matter. Lower case d is greater than upper case D.
- asciibetical
converts integers into their character equivalent. (ordinal to character)
print(chr(65))
A
print(chr(66))
B
print(chr(49))
1
print(chr(53))
5
U String
u'some string'
I think this was used in Python2 to specify a string to be encoded with unicode. But with Python3 unicode is the default encoding of strings so it is fairly irrelevant now?
Frequency and order does matter (contra dictionaries where order does not matter)
Thus, duplicates
Indexed with bracket notation
Composed of 'elements'
The empty list []
variables store lists as references to the list, not the list value itself
E.g., if you have two variables that are assigned to the same list, when you update the list via one variable, that list is updated for the other variable too.
Also, if you use a function's local variable to refer to a list, it will work to modify the list since even though the variable is local, it still refers to the list properly.
Python lets you make a list with mixed types, including other lists and also functions
example = [“string”, 73, [13, 15]]
Lists have an exception to indentation syntax - you can start a new line for each value, e.g., and python understands it's still a list via the [] which can be nice for readability and structuring your data.
Simplest, but doesn't give you access to index of list
for list_item in some_list: print(list_item)
With range(len(some_list))
More flexible since you have access to list index – e.g, you can refer to previous or next item in list with some_list[i-1]
for i in range(len(some_list)): print(some_list[i])
?With enumerate() to get access to both index and items themselves?
Initialization
example = []
example = [3, 7, 4, 7]
example = list()
creates empty list example
List Methods
Sorting Lists
.sort()
modifies the list in-place
return = None
sorted(simpsons, reverse=True)
sorted(simpsons, key=len)
.reverse()
return = None
list(reversed(weekdays))
alternative to [::-1] v
Asciibetical
easy way to make it regular alphabetical is to pass str.lower for the key keyword argument in the sort() method
spam.sort(key=str.lower)
.insert & .pop
Used to add and remove items at certain positions
example.insert(4, 62)
inserts the number 62 at position 4 and shifts over the elements after that. Ie, no elements are replaced.
example.pop()
deletes the last item in the list
example.pop(5)
deletes item at index 5
return value = the item deleted
list()
list('Evan')
Creates list of E, v, a, and n.
example.append(9)
return = None
example.remove(15)
removes the number 15 from the list (the first value it finds - starting from the first index I think)
example.remove("string")
Collection Iteration v
Nested Lists
Inner list is called a 'sublist'
someList[1][2]
Evaluated from left to right, so returns element at index 1, then in that list, returns the sublists index 2 element
Could also just assign the sublist to a variable and access it like a normal list
Update a Sublist
someList[2][1] = 'c'
List Concatenation & Replication
- Can combine lists (concatenation) but order still matters
- Numbers + letters returns differently ordered list than letters + numbers
- [1, 2] + [3, 4]
[1, 2, 3, 4]
- [0] * 4
[0, 0, 0, 0]
- more_fruit = fruit + ["kiwi"]
['apple', 'banana', 'kiwi']
- more_fruit = fruit + "kiwi"
error
- can't concatenate a string to a list. Can only concatenate lists with other lists.
List Repetition and Reference
- orig_list = [45, 76, 34, 55] print(orig_list * 3)
[45, 76, 34, 55, 45, 76, 34, 55, 45, 76, 34, 55]
- new_list = [orig_list] * 3 print(new_list)
[[45, 76, 34, 55], [45, 76, 34, 55], [45, 76, 34, 55]]
- new_list is a list of three references to orig_list that were created by the repetition operator.
- if we modify a value in orig_list:
- orig_list[1] = 99 print(new_list)
[[45, 99, 34, 55], [45, 99, 34, 55], [45, 99, 34, 55]]
- new_list shows the change in three places. This can easily be seen by noting that there is only one orig_list, so any changes to it appear in all three references from new_list.
- [orig_list] * 3 vs orig_list * 3
- The former creates a list of three references to orig_list
[[45, 76, 34, 55], [45, 76, 34, 55], [45, 76, 34, 55]]
- whereas the latter creates a new object using the values in orig_list
[45, 76, 34, 55, 45, 76, 34, 55, 45, 76, 34, 55]
List Comprehensions
omnioutliner:///open?row=pfaUbAC8UU0
Using Lists to Create Tables
Copy/Clone a List
Canonical way:
someList = [1, 2, 3] clonedList = someList[:]
clonedList = list(someList) is also just as/more valid
Creates 2 independent copies, where changes in each don't affect the other.
But will only make a shallow copy, so references inside lists e.g., might be affected. (Use copy.deepcopy())
del unary operator
del example[3]
deletes 4th item in list
del alist[1:5]
in and not in
omnioutliner:///open?row=d1uf_vHzJQn
example[0]
Returns value of 1st item, example[1], the 2nd item etc.
Example[-1]
Returns value of last item on list, example[-2] the 2nd to last etc.
my_list.pop(my_list.index(76))
Removes the element 76 via the .pop() method which gets the index from the .index() method
Return value of list methods like append is none so don't do spam = spam.append because they are done in place.
Tuples
Initialization
example = ()
example = (3, 7, 4, 7)
example = tuple()
Unlike lists, can use tuples as keys in dictionaries
Immutable
Cannot change data in a tuple as opposed to lists - immutable
can help since you can be confident another part of your program didn't modify it accidentally
Ordered
Elements of any type
Similar to lists but occupy less memory and have less modules. And sometimes it is nice to have something you know can’t change. Reliable.
Uses ()
What other languages call 'records'
Tuples are list-like collections so they behave Similarly
indexing
slicing
example[2]
accesses the value at that position in the tuple
my_tuple = tuple()
my_tuple = ()
tuple_with_only_one_value = (42,)
comma needed here
Use a comma after each element to specify it as a tuple
- You don’t technically need parentheses as long as they are separated by commas.
my_tuple = "one", "two", "three"
- If only one element, might need a comma to distinguish it from a parenthetical expression:
- (2,)
You can assign multiple values to a tuple all at once
a, b, c = (1, 2, 3,)
But the variable must match the number of values
Unpacking?
Data items stored within tuples are assigned variable names
(name, age) = tuple_or_list_name?
max() & min()
finds the largest or smallest value in a tuple of numbers (integers or floats)
Access specific position in a tuple that is in a list
list_name[0][1]
accesses the first item in the list, then returns the second item of the tuple, returns 100
Dictionaries
Initialization
example = {}
example = { “length”: 3, “width”: 4}
example = dict()
Called Maps or Hashmaps in other languages
Key-value pairs
Python’s built-in mapping type
Unordered
not ordered (contra lists). There is no "first" key-value pair in a dictionary.
Mutable
But the key is immutable
Key must be unique and can be a number or string
Key can be any immutable data type, including a tuple if its elements are also immutable
Value can be any data item you want
Can’t lookup the key from the value
“A Python dictionary is a list of key/value pairs, sometimes called a hash or associative array” or map, but each item in the dictionary is a pair - a key and a value.
the term "mapping" means linking one object to another, as in a dictionary key-value pair
One benefit to a dictionary is that you can reference the value by the key name
phonebook["Emma"]
dictionary variables hold a reference to the dictionary values, not the dictionary itself, (similar to lists)
Any object can be a dictionary value
A list, tuple, or dictionary, can be a value
Use a key to lookup a value, but you cannot use a value to lookup a key
A string or tuple can be a key, but not a list or dictionary
"The keys method returns what Python 3 calls a view of its underlying keys. We can iterate over the view or turn the view into a list by using the list conversion function."
.values()
Lists dictionary's values
return list-like data types
.items()
return list-like data types
key value pairs returned as tuples
e.g., for (k,v) in inventory.items():
.get()
.get(keyName)
it's tedious to always have to check if a key exists before getting its value so this helps avoid an error
Returns None if no key exists.
.get(key_name, “what to return if key not found in dictionary”)
Instead of returning None, returns the 2nd argument if given.
.setdefault()
returns the value of a key (if the key is in dictionary). If not, it inserts key with a value to the dictionary.
.update()
.update({“key_name”:value})
.pop()
.pop(key_name)
del
del phonebook['Julie']
deletes the 'Julie' entry (including the value, since they operate together, as pairs)
someVariable = someDictionary['someKey']
works as long as that key exists. If key doesn't exist, returns runtime error.
Thus, .get(), etc.
someDictionary['Julie'] = '913 547 9803'
adds new entry to the dictionary or changes the value at that key
Dictionary Iteration
for k in eggs.keys()
for v in eggs.values()
for k, v in eggs.items()
for k in inventory: print("Got", k, "that maps to", inventory[k])
for item in someDictionary
implicitly defaults to keys
Dictionary Copying/Cloning
copy & deepcopy methods
Make list of keys
key_list = list(inventory.keys())
Count number of each letter in a string Example
message = 'This is a sentence to count.' count = {} #We use .upper method to avoid counting upper and lower case letters differently. for character in message.upper(): count.setdefault(character, 0) count[character] = count[character] + 1
Countr Pairs Example
arr = [1, 3, 5, 3, 3, 3, 5] dict = {} for color in arr: dict.setdefault(color, 0) dict.update({color: dict.get(color) + 1})
Sparse Matrices
- "Since there is really no need to store all of the zeros, the “list of lists” representation is considered to be inefficient. A better representation is to use a dictionary. For the keys, we can use tuples that contain the row and column numbers. Here is the dictionary representation of the same matrix. matrix = {(0, 3): 1, (2, 1): 2, (4, 3): 3}"
- matrix[(0, 3)]
- There is one problem. If we specify an element that is zero, we get an error, because there is no entry in the dictionary with that key. The alternative version of the get method solves this problem. The first argument will be the key. The second argument is the value get should return if the key is not in the dictionary (which would be 0 since it is sparse).
- matrix = {(0, 3): 1, (2, 1): 2, (4, 3): 3} # Create the sparse matrix using a dictionary for i in range(5): for j in range(5): print(matrix.get((i, j), 0), "", end = '') print()
0 0 0 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 3 0
- Note: to suppress the endline terminator supplied by the print function, we add the optional argument end = ''. And to make the layout look nicer, we add an empty string to our print call.
Lists in Dictionaries
- someDict = {'a':[10,20,30], 'b':[20,30,40]} someDict['a'][1] = 50
[10, 50, 30]
- Update All Values in a List
- someDict['b'] = [x+1 for x in someDict['b']]
pprint() & pprint.pformat()
prints dictionaries in a much more readable way, e.g. lined up vertically
Sets
Frequency and order don’t matter
my_set = {3, 5, 6}
example = set()
example.add(3)
example.remove(3)
example.clear()
example.discard(3)
example = set([3, 2, 1])
prepopulates
remove
Throws an error if that value is not in the set
discard
Doesn’t throw an error if the value isn’t in the set
Basically, Python lists are very flexible and can hold completely heterogeneous, arbitrary data, and they can be appended to very efficiently, in amortized constant time. If you need to shrink and grow your array time-efficiently and without hassle, they are the way to go. But they use a lot more space than C arrays. The array.array type, on the other hand, is just a thin wrapper on C arrays. It can hold only homogeneous data, all of the same type, and so it uses only sizeof(one object) * length bytes of memory. Mostly, you should use it when you need to expose a C array to an extension or a system call (for example, ioctl or fctnl).
However, if you want to do math on a homogeneous array of numeric data, then you're much better off using NumPy, which can automatically vectorize operations on complex multi-dimensional arrays. To make a long story short: array.array is useful when you need a homogeneous C array of data for reasons other than doing math.
Most popular use of arrays is via numPy
someArray = array([1, 3, 6, 9, 12, 15])
All of the same data type (contra lists)
Arrays should allow stuff like this (directly performing operation on all items) (contrary to lists which would error):
- x = array([3, 6, 9, 12]) x/3.0 print(x)
array([1, 2, 3, 4])
Stacks
Queues
JSON
JSON module
JSON doesn’t support comments
Use config.json.example with example values so the user can rename to config.json with their own values.
Indexing & Slicing
Bracket Notation
Slicing
(Also for strings)
First number inclusive, second number exclusive, like range
If 3rd number given it's the step, as in 2, every other number
Negative numbers count backwards and can be in any position
example[:5]
items up to 5
example[5:]
Items from 5 to the end
example[-3:]
Last 3 items - start from the 3rd to last item until the end
[1::4]
From index 1 to the end, return every 4th index, including index 1.
[1:-1]
from index 1 to the second to last item
[::-1]
When a negative number is used as the step, it counts backwards.
Common way to reverse a list or string
[::2]
start at beginning, go to the end, but take every 2nd element
so [1, 2, 3, 4][::2] = [1,3]
Negative Indexing
-1 to get the last item in the list, -2, second to last, etc.
index()
.index()
strings, lists
Like find except causes a runtime error if item is not found
rindex() only works on strings
Splitting & Joining
Lists and strings, more?
.split()
- Delimiter goes in (), defaults to space if unspecified
- Any number of spaces will work as the delimiter
- The delimiter is excluded in the resulting list
- The string is not itself modified, of course since strings are immutable
- 'some text I wrote'.split()
['some', 'text', 'I', 'wrote']
- 'this, that, and that one, thing'.split(",")
['this', ' that', ' and that one', ' thing']
- splits items separated by a comma
.join()
- .join(someList) on a separator string, aka the glue
- Interpolate a character
- Note that it only operates in the spaces between elements, ie, it doesn't add the glue to the last element.
- The list whose elements you glued together is not itself modified
- Join a String
- my_string = 'abc' result = '+'.join(my_string)
'a+b+c'
- Join a List
- my_list = ['a', 'b', 'c'] result = '; '.join(my_list)
'a; b; c'
- Join with empty/no Separator
- ''.join(['a', 'b', 'c'])
'abc'
- Join with multi-character Separator
- 'xyz'.join(['a', 'b', 'c'])
'axyzbxyzc'
list('Evan')
splits string into individual letters
len()
string, lists
# of characters in a string
# of elements in a list (doesn't include elements inside a nested list)
# of key-value pairs in a dictionary
tuples
.count()
strings, lists
simpsons.count('lisa')
Returns the number of occurrences of item
Boolean Container Membership Operators (in and not in)
omnioutliner:///open?row=d1uf_vHzJQn
Collection Iteration v
Strings are essentially lists in Python so a lot of the functions carry over
You can store a tuple in a list, a list in a tuple, & a dictionary in a list or tuple
Python Control Flow
Conditionals
if, elif, else
Binary Selection:
if, else
Unary Selection:
if statement only
Chained Conditional:
if, elif, else
Switch (Python does not have it)
You could implement it if needed.
Ternary Operator/Conditional Expression
x if C else y
e.g.
user_input = "" if user_input is None else user_input * 2
? : in other languages like Java and Javascript
Ternary Operator
omnioutliner:///open?row=jKuYD4BdrbM
Emulate Logical iff?
aka "if and only if" or p ⟷ q
kind of unnecessary given how computers work I think. You're checking state in CS, vs declaring an eternal truth value in the abstract math/logic/truth table realm. p ⟷ q but at any given time p or q could change value. Not so in logic/math.
if p and q
if not p and not q
There is no limit on the number of statements that can appear under the two clauses of an if statement, but there has to be at least one statement in each block. Also, note that each if statement can have only one else clause.
Iteration
Loops
- For Loops
- for n in range(0, 100):
- Prints 0-99 - range includes lower bound, excludes the upper
- range(4) produces 0,1,2,3
- for i in range(0, 10, 2)
- 2, 4, 6, 8
- You can use -1 step argument to count backwards by one.
- range is a list like data structure (An iteratior?)
- list(range(4))
- For loops technically iterate over a list or list like data structure
- else:
- While Loops
- while True:
- else:
- Break & Continue
- Only usable in while and for loops?
- break
- Immediately exits the loop
- Useful to e.g. have conditions to exit the loop separate from the loop’s initial condition
- continue
- Immediately jumps to the start of the loop and reevaluates the condition
- Collection Iteration (for-each Loops)
- When considering this structure, it can be helpful to read the code sample above to yourself as “For each integer in list nums…”.
- for...in
- for item in someList:
- for char in someString:
- For loop over a range of list data
words = ["cat", "dog", "horse"] for word in words: print(word)
- Lists
- Strings
- for char in "abcdefghijklmnopqrstuvwxyz":
- Manually with for or while Loops
- fruit = "apple" for index in range(len(fruit)): print(fruit[index])
- fruit = "apple" position = 0 while position < len(fruit): print(fruit[position]) position = position + 1
- Collection Iteration With counter variable via enumerate()
- omnioutliner:///open?row=i22bU1oVbFt
- https://www.codejava.net/java-core/collections/the-4-methods-for-iterating-collections-in-java
- Dictionary Iteration
- in
- You can use else: in for and while loops:
- Uncommonly known, but can be very useful
- Else is run when the entire loop is run to completion/exited naturally (no breaks, etc.)
- e.g. using a loop to search for something. Normally you need to set a flag and then maybe need to check for the flag to do something. This is cleaner, simpler, more readable, and more pythonic/zen of python.
- for x in data: if meets_condition(x): break else: # raise error or do additional processing if loop body never accessed - exits naturally
- Nested Loops
- Outer Loop
- Inner Loop
- No limit to how many you can nest
- You can nest a for loop in a while or vice versa etc.
Iteration, Iterable, Iterator Terms
In Python, iterable and iterator have specific meanings.
Iteration
The general process of taking one element at a time - canonically, a loop
Iterable
The object that is able to be iterated over - keep returning the next object, like range & enumerate.
Generally, anything that can be looped over - a string, list, file, etc.
In Python, an iterable is an object that has an __iter__ method which returns an iterator, or which defines a __getitem__ method that can take sequential indexes starting from zero (and raises an IndexError when the indexes are no longer valid). So an iterable is an object that you can get an iterator from.
Iterator
How you get the next item, how you do the iteration
an object with a next (Python 2) or __next__ (Python 3) method.
returns next value in iteration
updates state to point to next value
signals when it is done by raising StopIteration
Has state that remembers where it is during iteration
self iterable? has an __iter__ method that returns itself?
List Comprehensions
- Concise way to create lists
- General Syntax: [ for in if ] where if clause is optional
- expression is performed last, after each item is chosen and the optional conditional is ran to see if it is in fact added, then the expression, last.
- cubes = [i**3 for i in range(5)]
- evens = [i**2 for i in range(10) if i**2 % 2 == ]
- my_list = [1,2,3,4,5] your_list = [item ** 2 for item in my_list]
[1, 4, 9, 16, 25]
- result = [num for num in range(2,n) if is_prime(num)]
- alist = [4,2,8,6,5] blist = [num*2 for num in alist if num%2==1]
[10]
Generators
- simple functions which return an iterable set of items, one at a time, in a special way. Ie, creates iterators
- Anything that can be done with generators can be done with class-based iterators, but the big benefit of generators is their compactness and simplicity. E.g., they automatically create their __iter__() and __next__() methods and automatically raise StopIteration when they terminate.
- Local variables and execution state are automatically saved between calls which is better than the class-based approach via instance variables like self.index and self.data.
- General Example
- def squares(start, stop): for i in range(start, stop): yield i * i generator = squares(2, 5) for i in generator: print(i) # Optionally could've just said: # for i in squares(2,5): print(i)
4 9 16
- or the equivalent generator expression (genexp) generator = (i*i for i in range(2, 5)) for i in generator: print(i)
4 9 16
- Generator Expressions
- Some simple generators can be coded succinctly as expressions using a syntax similar to list comprehensions but with parentheses instead of square brackets. These expressions are designed for situations where the generator is used right away by an enclosing function. Generator expressions are more compact but less versatile than full generator definitions and tend to be more memory friendly than equivalent list comprehensions.
enumerate()
- Way to avoid needing to manually specify an index loop variable (index = 0, index +=1) when you need to keep track of the iteration count in addition to a container iteration (for item in someList:)
- instead of: tennis_champs = ["Serena Williams", "Simona Halep", "Caroline Wozniacki", "Angelique Kerber", "Elina Svitolina"] index = 1 for competitor in tennis_champs: print(index, competitor) index += 1
1 Serena Williams 2 Simona Halep 3 Caroline Wozniacki 4 Angelique Kerber
5 Elina Svitolina
- enumerate() allows: tennis_champs = ["Serena Williams", "Simona Halep", "Caroline Wozniacki", "Angelique Kerber", "Elina Svitolina"] for index, competitor in enumerate(tennis_champs, 1): print(index, competitor)
- by default, the index for enumerate begins at 0, but we can specify what to start the index with in the () of enumerate
- Store Index & List Elements in a Dictionary
- tennis_champs = ["Serena Williams", "Simona Halep", "Caroline Wozniacki", "Angelique Kerber", "Elina Svitolina"] champs_dictionary = dict(enumerate(tennis_champs, 1))
{1: 'Serena Williams', 2: 'Simona Halep', 3: 'Caroline Wozniacki', 4:
'Angelique Kerber', 5: 'Elina Svitolina'}
- Store Index & List Elements in a List of Tuples
- tennis_champs = ["Serena Williams", "Simona Halep", "Caroline Wozniacki", "Angelique Kerber", "Elina Svitolina"] champs_tuples = list(enumerate(tennis_champs, 1))
[(1, 'Serena Williams'), (2, 'Simona Halep'), (3, 'Caroline
Wozniacki'), (4, 'Angelique Kerber'), (5, 'Elina Svitolina')]
Exception/Error Handling
try, except, else, & finally
You can avoid errors crashing your program and account for them by enclosing the code you want to catch errors in in a try block and the name of the error as the condition in the except block. If there’s an error of that name the try block will skip the rest of its code and jump to the except block and execute all its code and then exit the whole try block.
try:
You can next these too
except:
You can name the error as a condition in the except block or not name it to catch any error.
except ZeroDivisionError:
You can have as many except blocks as you want
You can list multiple error names in a single block - except (ValueError, TypeError):
potentially can have multiple exceptions that each run its except block?
Be careful using variables in an except block that were assigned in a try block since they might not have been assigned due to the exception possibly being raised before the assignment.
else:
if there's no exception - what you only want to exceute if everything went smoothly.
But you can't use both finally and else?
finally:
placed at the bottom of a try, except block
code will run no matter what error occurs, either after the try block or after the except block depending.
Code in the finally block runs even in the event of an uncaught exception above.
Uses an __enter__ and __exit__ functions to guarantee teardown code will run even with exceptions
raise
- Can use builtin errors or just name your own
- Can optionally add a string to describe more.
- raise my_error_code
- raise another_error("You made an error")
another_error: You made an error
- Can be used in an except block to re-raise whatever exception occurred
assert
- assert 2 + 2 == 4
- A sanity check to test the program
- An expression is checked and if the result is False, an exception is raised called, AssertionError
- AssertionError exceptions can be caught and handled like any other exception using the try/except statement, but if not handled, assertion errors terminate the program.
- assert (temp >= 0), "Colder than absolute zero"
AssertionError: Colder than absolute zero
Exception object
Print name of exception
except Exception as e: print(e.__class__.__name__)
Base class for all exceptions. This catches most exception messages.
Kinds of Errors
Syntax Errors
fatal
Exceptions
not fatal
can be handled with exception handling
Standard Exceptions
All exceptions are objects. The classes that define the objects are organized in a hierarchy, which is shown below. This is important because the parent class of a set of related exceptions will catch all exception messages for itself and its child exceptions. For example, an ArithmeticError exception will catch itself and all FloatingPointError, OverflowError, and ZeroDivisionError exceptions.:
BaseException
SystemExit
KeyboardInterrupt
GeneratorExit
Exception
StopIteration
StopAsyncIteration
ArithmeticError
FloatingPointError
OverflowError
ZeroDivisionError
AssertionError
AttributeError
BufferError
EOFError
ImportError
LookupError
IndexError
KeyError
MemoryError
NameError
UnboundLocalError
OSError
BlockingIOError
ChildProcessError
ConnectionError
BrokenPipeError
ConnectionAbortedError
ConnectionRefusedError
ConnectionResetError
FileExistsError
FileNotFoundError
InterruptedError
IsADirectoryError
NotADirectoryError
PermissionError
ProcessLookupError
TimeoutError
ReferenceError
RuntimeError
NotImplementedError
RecursionError
SyntaxError
IndentationError
TabError
SystemError
TypeError
ValueError
UnicodeError
UnicodeDecodeError
UnicodeEncodeError
UnicodeTranslateError
Warning
DeprecationWarning
PendingDeprecationWarning
RuntimeWarning
SyntaxWarning
UserWarning
FutureWarning
ImportWarning
UnicodeWarning
BytesWarning
ResourceWarning
Language Exceptions
StandardError
Base class for all built-in exceptions except StopIteration and SystemExit.
ImportError
Raised when an import statement fails.
SyntaxError
Raised when there is an error in Python syntax.
IndentationError
Raised when indentation is not specified properly.
NameError
Raised when an identifier is not found in the local or global namespace.
Name errors almost always mean that you have used a variable before it has a value. Often name errors are simply caused by typos in your code. They can be hard to spot if you don’t have a good eye for catching spelling mistakes.
UnboundLocalError
Raised when trying to access a local variable in a function or method but no value has been assigned to it.
TypeError
Raised when an operation or function is attempted that is invalid for the specified data type.
LookupError
Base class for all lookup errors.
IndexError
Raised when an index is not found in a sequence.
KeyError
Raised when the specified key is not found in the dictionary.
ValueError
Raised when the built-in function for a data type has the valid type of arguments, but the arguments have invalid values specified.
RuntimeError
Raised when a generated error does not fall into any category.
MemoryError
Raised when a operation runs our of memory.
RecursionError
Raised when the maximum recursion depth has been exceeded.
SystemError
Raised when the interpreter finds an internal problem, but when this error is encountered the Python interpreter does not exit.
Math Exceptions
ArithmeticError
Base class for all errors that occur for numeric calculation. You know a math error occurred, but you don’t know the specific error.
OverflowError
Raised when a calculation exceeds maximum limit for a numeric type.
FloatingPointError
Raised when a floating point calculation fails.
ZeroDivisionError
Raised when division or modulo by zero takes place for all numeric types.
I/O Exceptions
FileNotFoundError
Raised when a file or directory is requested but doesn’t exist.
IOError
Raised when an input/ output operation fails, such as the print statement or the open() function when trying to open a file that does not exist. Also raised for operating system-related errors.
PermissionError
Raised when trying to run an operation without the adequate access rights.
EOFError
Raised when there is no input from either the raw_input() or input() function and the end of file is reached.
KeyboardInterrupt
Raised when the user interrupts program execution, usually by pressing Ctrl+c.
Other Exceptions
StopIteration
Raised when the next() method of an iterator does not point to any object.
AssertionError
Raised in case of failure of the Assert statement.
SystemExit
Raised when Python interpreter is quit by using the sys.exit() function. If not handled in the code, it causes the interpreter to exit.
OSError
Raises for operating system related errors.
EnvironmentError
Base class for all exceptions that occur outside the Python environment.
AttributeError
Raised in case of failure of an attribute reference or assignment.
NotImplementedError
Raised when an abstract method that needs to be implemented in an inherited class is not actually implemented.
Exception Examples
Catch All Exceptions
try: # Your normal code goes here. # Your code should include function calls which might raise exceptions. except: # If ANY exception was raised, then execute this code block.
Catch all exceptions, regardless of their type. This will prevent your program from crashing, but this type of exception handling is rarely useful because you can’t do anything meaningful to recover from the abnormal condition. In fact, you don’t even know what the abnormal condition is since it could be any exception.
Catch a Specific Exception
try: # Your normal code goes here. # Your code should include function calls which might raise exceptions. except ExceptionName: # If ExceptionName was raised, then execute this block.
This is perhaps the most often used syntax. It catches one specific condition and tries to recover from the condition.
Catch Multiple Specific Exceptions
try: # Your normal code goes here. # Your code should include function calls which might raise exceptions. except ExceptionOne: # If ExceptionOne was raised, then execute this block. except ExceptionTwo: # If ExceptionTwo was raised, then execute this block. else: # If there was no exception then execute this block.
If you are writing a code block that contains calls to functions that may raise multiple different exceptions, then you can write separate except clauses to handle each. You may also include an elseclause after your except clauses to contain any code that you want to run in case the try clause does not raise an exception.
Be aware that when you have more than one except clause in a try: except; block, it is only the first matching exception that will be triggered and have its code block executed. Therefore, you want to list the exceptions in the order of more specific to less specific. For example, you saw in the lesson on Standard Exceptions that the ZeroDivisionError is a “child” of the ArithmeticError. This means that the former is more specific than the latter. So if you want to catch both errors because you want to do different things based on which error it is, then you would want to list the except clause for the ZeroDivisionError first.
Clean-up After Exceptions
try: # Your normal code goes here. # Your code might include function calls which might raise exceptions. # If an exception is raised, some of these statements might not be executed. finally: # This block of code will always execute, even if there are exceptions raised
If you have code that you want to be executed even if exceptions occur, you can include a finally code block
File I/O
try: f = open("my_file.txt", "w") try: f.write("Writing some data to the file") finally: f.close() except IOError: print("Error: my_file.txt does not exist or it can't be opened for output.")
one place where you will always want to include exception handling is when you read or write to a file. Here is a typical example of file processing. Note that the outer try: except: block takes care of a missing file or the fact that the existing file can’t be opened for writing. The inner try: except: block protects against output errors, such as trying to write to a device that is full. The finally code guarantees that the file is closed properly, even if there are errors during writing.
Input Validation
Use a custom class to define specific Errors
one benefit is that the error message can contain 1) a descriptively named error 2) a custom descriptive string and 3) the actual value that caused the error to be raised - like a variable name or a string.
Think Python Book Principles of Exceptions
There are many bad examples of exception use on the Internet. The purpose of an exception is to modify the flow of control, not to catch simple errors. If your try: except: block is in the same function that raises the exception, you are probably misusing exceptions.
Principle 1
If a condition can be handled using the normal flow of control, don’t use an exception!
ie, try to use if/else statements to handle the logic and flow and reaction to conditions
e.g. you can just code a useful reaction to a input being zero when dividing by zero instead of catching the exception
Principle 2
If you call a function that potentially raises exceptions, and you can do something appropriate to deal with the exception, then surround the code that contains the function call with a try: except:block.
Principle 3
If you call a function that potentially raises exceptions, and you can’t do anything meaningful about the conditions that are raised, then don’t catch the exception message(s).
e.g., if you can't access the database due to authentication error, maybe its better for the program to crash instead of running as if nothing's catastrophically wrong.
From LC101
Tom Lynch 6:45 PM It can be useful to create your own exception types, since the type of the exception will be printed out in the stack trace, which can aid debugging. That said, I usually use ValueError and rarely create my own types of exceptions. 00 Tom Lynch 6:47 PM NotImplementedError and StopIteration are two additional examples of commonly used exceptions. Unlike some other languages, Python heavily makes use of exceptions for flow control--StopIteration is an example.
Exceptions are often defined as being “errors” but that is not always the case. Programmers can create exceptions in response to any special situation — not just an error — that they think it would be useful to change the flow of control to handle. In other words, all errors in Python are dealt with using exceptions, but not all exceptions are errors.
there are cases where this sequential flow of control does not work well. An example will best demonstrate this.
It would be very helpful if function d could communicate directly with main (or any other function) without having to send a special value through the intermediate calling functions. Well, that is exactly what an exception does. An exception is a message to any function currently on the executing program’s run-time stack. (The run-time stack is what keeps track of the active function calls while a program is executing. It is also known as a call stack.)
So what happens to an exception message after it is created? The normal flow of control of a Python program is interrupted and Python starts looking for any code in its run-time stack that is interested in dealing with the message. It always searches from its current location at the bottom of the run-time stack, up the stack, in the order the functions were originally called. A try: except: block is used to say “hey, I can deal with that message.” The first try: except: block that Python finds on its search back up the run-time stack will be executed. If there is no try: except: block found, the program “crashes” and prints its run-time stack to the console.
the Pythonic naming convention for exceptions is to use the CapWords case. It is also conventional for the last word of the exception name to be “Error”, if the exception is indeed an error.
Careful with assigning variables in try block since that code might not get run correctly if there is an exception that exits the block
Program Termination
sys.exit()
Pause Execution
time.sleep() v
Python Quantitative Programming
Operators
Math Operators
- +
- Can also concatenate strings
- -
- *
- Can also do string replication
- /
- **
- Exponent
- %
- modulo
- Modulus/remainder
- E.g.
- 22 % 7 = 1
- The modulus turns out to be surprisingly useful. For example, you can check whether one number is divisible by another—if x % y is zero, then x is divisible by y. This makes it easy to determine if a number is even, for example. You just need to check if num % 2 == 0. Also, you can extract the right-most digit or digits from a number. For example, x % 10 yields the right-most digit of x (in base 10). Similarly x % 100 yields the last two digits.
- Finally, returning to our time example, the remainder operator is extremely useful for doing conversions, say from seconds to hours or minutes. If we start with a number of seconds, say 7684, the following program uses integer division and the modulo operator to convert to an easier form. Step through it to be sure you understand how the division and remainder operators are being used to compute the correct values.
- total_secs = 7684 hours = total_secs // 3600 secs_still_remaining = total_secs % 3600 minutes = secs_still_remaining // 60 secs_finally_remaining = secs_still_remaining % 60
- //
- Integer division/floored quotient
- doesn't return remainder
- E.g.
- 22 // 7 = 3
- Also good to get an integer instead of a float.
- 21 / 3
7.0
- 21 // 3
7
Assignment Operators
=
+=
-=
*=
/=
%= ?
//= ?
Python doesn't have a ++ operator, just use += 1 instead
if a, b, c, …, y, z are expressions and op1, op2, …, opN are comparison operators, then a op1 b op2 c … y opN z is equivalent to a op1 b and b op2 c and … y opN z, except that each expression is evaluated at most once.
a op1 b op2 c doesn’t imply any kind of comparison between a and c, so a < b > c is perfectly legal.
x < y < z which means the same as its mathematical expression and is functionally equivalent to the Python expression x < y and y < z
this is contrary to symbolic logic where you need x < y and y < z
Identity Comparison Operators
Identity & Equality v
is
object identity: x is y is true if and only if x and y are the same object/same identity/identical – point to the same object in memory
contra == which compares values (normally)
is not
Common to check a variable: if x is None:
Object Checking (isinstance(), type(), __eq__, __ne__) v
Boolean Operators
and
or
not
Boolean Collection Membership Operators
(name for these?)
in
not in
Doesn't count elements inside a nested list
all()
any()
'nice' in someString
'day' not in someString
'someKey' in someDictionary
Checks keys, not values in dictionaries
'apple' in someList
Order of Operations (Precedence)
PEMDAS
Operators with the same precedence are evaluated from left-to-right. In algebra we say they are left-associative.
Due to some historical quirk, an exception to the left-to-right left-associative rule is the exponentiation operator **. A useful hint is to always use parentheses to force exactly the order you want when exponentiation is involved:
print(2 ** 3 ** 2) # the right-most ** operator gets done first! print((2 ** 3) ** 2) # use parentheses to force the order you want!
exponent: **
multiplication: * / // %
addition: + -
relational: == != <= >= < >
logical: not
logical: and
logical: or
Ternary Operator/Conditional Expression
Ternary Conditional
omnioutliner:///open?row=kAXCpHto6Gs
Bitwise Operators
<<=
>>=
&=
^=
|=
Math & Science
Random Numbers
Random Module
import random
random.randint(0, 1024)
inclusive of upper and lower bound
random.randrange(1, 7)
upper bound exclusive
random.randrange(start, stop, step)
random.randrange(0, 200, 7)
start, stop, step
choose from 0 to 199 or 200? in steps of 7
random.random()
returns floating point number between 0.0 and 1.0
0.0 inclusive, to 1.0 exclusive or [0.0, 1.0)
common to scale it by multiplication:
prob = random.random() result = prob * 5
random.uniform
Allows you to automatically shift to any scale?
Discrete
random.randint(min, max) #random integer
Randomly choose from a list
random.choice()
outcomes = [choice1, choice2, choice3]
for i in range(10):
random.choice(outcomes)
Or simply, random.choice(["foo", "bar", "spam"])
Shuffle
random.shuffle(desserts)
Shuffles a list randomly
Coin Toss
random.normalvariate(mean, std deviation)
[0,1) includes 0, does not include 1
random.shuffle()
shuffles a list
e.g. to shuffle the list before you select from it.
UUID Module
import uuid
uuid.uuid4()
pretty secure way of generating random numbers, more secure than randint
Uniform distribution
Each number is equally likely to be chosen
Normal or bell distribution
Bell curve
Mean + standard deviation
pseudo-random number generator
Random Selection From an Array
Rounding to Decimal Places
Floating Point Precision
Binary
bin(3)
format(3, 'b')
Scientific Notation
- 1.1e3
1100
Math Module
math.sqrt()
Numpy Module
Scipy Module
Statistics Module
statistics.mean()
statistics.median()
statistics.mode()
round()
- round(2.7874534, 2)
2.78
- There is some weirdness with floats - sometimes it just truncates instead of rounding up or down due to floating point arithmetic stuff.
abs()
min()
max()
sum()
Works with dictionaries, lists, etc.
sum(students.values())
Format/precision to a given number of decimal places
format(average, '.2f')
Date & Time
Pause Execution
time.sleep() v
Time Module
- Time Function's Nine Tuples
- Index, Fields, Values
- 0, 4-digit year, 2018
- 1, Month, 1 to 12
- 2, Day, 1 to 31
- 3, Hour, 0 to 23
- 4, Minute, 0 to 59
- 5, Second, 0 to 61 (60 or 61 are leap-seconds)
- 6, Day of Week, 0 to 6 (0 is Monday)
- 7, Day of year, 1 to 366 (Julian day)
- 8, Daylight savings, -1, 0, 1 (-1 means library determines DST)
- time.asctime()
- returns current time as a string
- can also be used to take datetimes in the form of the standard tuple format (below) and convert it to display something more readable
- e.g.
import time t = (2020, 2, 23, 10, 30, 48, 6, 0, 0)
print(time.asctime(t)) Sun Feb 23 10:30:48 2020
- time.strftime()
- time.strftime("%a")
- 'Thu'
- time.strftime("%B")
- 'September'
- time.strftime("%b")
- 'Sep'
- time.strftime("%H")
- '09'
- time.strftime("%H%M")
- '0941
- time.strftime("%H:%M")
- '09:41'
- time.time()
- seconds and nanoseconds?
- unix time
- good for simple counters/stopwatch/clocking of a given process
- time.local.time()
- shows the structure of how time is presented
- e.g.
print(time.localtime()) time.struct_time(tm_year=2020, tm_mon=2,
tm_mday=23, tm_hour=22, tm_min=18, tm_sec=39, tm_wday=0,
tm_yday=73, tm_isdst=0)
- And then you can print whatever part of that with index positions:
t = time.localtime() year = t[0] month = t[1] print(year)
print(month) 2020 2
- time.sleep()
- time.sleep(10)
Datetime Module
Calendar Module
Python IO
Input
input()
age = input("How old are you?")
sys.stdin
text = sys.stdin.readline()
requires sys module
I don't know why you'd use this instead of input.
One benefit to the sys method is you can specify how many characters to read in
v = sys.stdin.readline(13)
will capture only the first 13 chars entered.
Output
print()
print("Hello world!")
You can use a comma to separate variables which automatically inserts a space between them, in contrast to a+b.
print() prints blank line
/n Is implicitly added to the end of every print() call
sep=‘’
Specify what is between each item when printing multiple items, e.g. sep=‘,’
end=‘’
Specify what the end character is, e.g. to not print /n but just have spaces between on the same line end=‘ ‘
default is to also return the number of chars printed, which you could save to a variable if you wanted to keep track of that.
Pretty Printing
pprint() & pprint.pformat()
Colorama Module
Files
Opening, Reading, & Writing Files
- Opening
- open()
- poem=open("/path/to/file.txt")
- If the file is in the same location as the program you only need the file name, not the full path
- poem=open("/path/to/file.txt","w")
open file in write mode
- Access Modes
- r
- read
- defaults to read if not specified.
- w
- write
- w+
- Reading and writing
- a
- append
- b
- binary
- r+
- read and write and places the cursor at the start?
- Best Practice For Opening Files - use with:
- with open ("file.txt", "r") as f: content = f.read() # Python still executes f.close() even though an exception occurs 1 / 0
- This is the safest way to open a file. The file class has some special built-in methods called __enter__() and __exit__() which are automatically called when the file is opened and closed, respectively. Python guarantees that these special methods are always called, even if an exception occurs.
- Good Practice to use try and finally when working with files to make sure they are always closed after. Put close() in finally block. But I think errors might still prevent finally in some cases
- Or a simpler way to make sure no errors prevent closing is to use:
with open(“file name.txt”) as f: print(f.read())
- File is automatically closed even if there are exceptions.
- Reading
- we need to reopen the file before each read so that we start from the beginning. Each file has a marker that denotes the current read position in the file. Any time one of the read methods is called the marker is moved to the character immediately following the last character returned. In the case of readline this moves the marker to the first character of the next line in the file. In the case of read or readlines the marker is moved to the end of the file.
- read()
- read the entire file into a single string
- I think it returns the data from the file sequentially such that if you read the whole file, there's nothing left for you to read if you try to read again without recreating the file object/variable thing? E.g., read(5), read(5) outputs the first 5 characters and then the next 5 characters
- read(5)
- reads the next 5 characters
- readline()
- reads a single line from the file, up to and including the first \n character
- returns the empty string when it reaches the end of the file.
- e.g.
line = poem.readline() line
- infile = open("qbdata.txt", "r") line = infile.readline() while line: values = line.split() print('QB ', values[0], values[1], 'had a rating of ', values[10] ) line = infile.readline() infile.close()
- The important thing to notice is that on line 2 we have the statement line = infile.readline(). We call this initial read the priming read. It is very important because the while condition needs to have a value for the line variable. The readline method will return the empty string if there is no more data in the file. The condition while line: means while the content of line is not the empty string. Remember that a blank line in the file actually has a single character, the \n character (newline). So, the only way that a line of data from the file can be empty is if you are reading at the end of the file. Finally, notice that the last line of the body of the while loop performs another readline. This statement will reassign the variable line to the next line of the file. It represents the change of statethat is necessary for the iteration to function correctly. Without it, there would be an infinite loop processing the same line of data over and over.
- readline(n)
- returns n characters of each line
- readlines()
- grabs all the lines of a text where each individual line is a string in a list
- e.g., store lines as a list and reference the list by list index number
lines = poem.readlines() lines[0] lines[1]
- e.g., print each line with a for loop
lines = poem.readlines() for i in lines: print(i)
- e.g., builtin way of printing lines in a loop?
poem=open("/Users/evan/Dropbox/Programming/Python/rose.txt") for lines
in poem: print(lines)
- readlines(n)
- Returns a list of strings, each representing a single line of the file. If n is not provided then all lines of the file are returned. If n is provided then n characters are read but n is rounded up so that an entire line is returned.
- for line in my_file: print(line)
- Writing
- write()
- e.g.
memo=open("/path/to/file.txt","w") memo.write("This is the text.")
- If there is not a file named that at that location it will create one there. If there is one there, it will overwrite it, so be careful.
- But the actual file won't have these changes committed to it until you use memo.close().
- Adds the string to the end of the file
- Add \n if you want to add multiple lines
- Closing
- close()
- Pickle Module
- I think it's mostly deprecated for security reasons
- Used for converting python objects into something that can be written into a file and then easily read back out.
- Save a dictionary
import pickle dictionary1 = {} save_file = open('save.dat', 'wb')
pickle.dump(dictionary1, save_file) save_file.close()
- unpickle
load_file = open('save.dat', 'rb') loaded_game_data =
pickle.load(load_file) load_file.close()
CSV
CSV Module
lines[0]
lines[0].strip()
Removes white space
lines[0].strip().split()
Divides each line into smaller pieces
import csv
The Self-Taught Programmer Challenge Example
movies = [["Top Gun", "Risky Business", "Minority Repot"], ["Titanic", "The Revenant", "Inception"], ["Training Day", "Man on Fire", "Flight"]] base_dir = os.path.join("files", "csv") with open(os.path.join(base_dir, "movies.csv"), "w", newline='') as f: w = csv.writer(f, delimiter=",") for row in movies: w.writerow(row)
File Paths
Cory Althoff: don't write file paths manually. Use os.path to generate them so they are crossplatform
import os os.path.join("Users", "bob", "someFile.txt")
Example:
import os base_dir = os.path.join("files", "notes") print(base_dir) with open(os.path.join(base_dir, "meepreadme.md"), "r") as f: print(f.read()) # Alternatively with variables response = input("What do you want to add to a file?") new_filename = "new_file.txt" save_location = os.path.join(base_dir, new_filename) with open(save_location, "w") as f: f.write(response)
import turtle wn = turtle.Screen() wn.bgcolor("lightgreen") # set the window background color tess = turtle.Turtle() tess.color("blue") # make tess blue tess.pensize(3) # set the width of her pen tess.forward(150) tess.left(120) tess.forward(150) wn.exitonclick()
Pygame Module
- import pygame
- Already installed on Raspbian
- Import and display an image
import pygame pygame.init()
img = pygame.image.load("RPi.png")
white = (255, 255, 255) w = 900 h = 450 screen
=pygame.display.set_mode((w, h)) screen.fill((white))
screen.fill((white)) screen.blit(img,(0,0)) pygame.display.flip()
While True: for event in pygame.event.get(): if event.type ==
pygame.QUIT: pygame.quit()
I think there's a Udemy course on pandas I own too
bokeh
matplotlib
seaborn
plotly
altair
vega-lite
Issues
Global and Local Scope Example from ATBS
def spam(): print(eggs) # error eggs = 'spam local'
eggs = 'global' spam() Local variable referenced before assignment
I understand the rule, but it would seem to violate my understanding of the line by line execution of Python programs. I thought the local eggs assignment being after the print function would mean that the program would not 'know' about it and thus would print the global variable ok even if there might be an error on the next line. What exactly is happening? What do you call that fact? And in what other ways does this happen? Like precompiling or analyzing or something? Is this kind of thing much more common with compiled languages vs interpretd? Because it seems the vast majority of the time you can reason pretty definitively about line by line execution in Python at least.
Why doesn't declaring the variable step as global within the conditionals work - it works when step is declared first, outside the conditionals, but inside the function.
def collatz(number): if number % 2 == 0: global step step = number // 2
print(step) return step elif number % 2 == 1: global step step = 3 *
number + 1 print(step) return step
global step step = int(input("Type an integer: "))
collatz(step) collatz(step)
What exactly is the i in for i loops? Is it technically local? Or different in some way? The below used name variable when it was used previously. So it seems like it’s being used locally sort of.
“for name in catNames: print(' ' + name)” Excerpt From Automate the Boring Stuff with Python: Practical Programming for Total Beginners Al Sweigart This material may be protected by copyright.
Why does this program actual run the function mainMenu()? It seems like it just assigns the function to the variable, not actually call the function.
Example program from BDM's Coding for Beginner's magazine
Program lets users create usernames and passwords, login to the "system", log their time, and quit
import time
users = {} status = ""
def mainMenu(): global status status = input("Do you have a login
account? y/n? Or press q to quit.") if status == "y": oldUser() elif
status == "n": newUser() elif status == "q": quit()
def newUser(): createLogin = input("Create a login name: ") if
createLogin in users: print ("name already exists!") else: createPassw =
input("Create a password: ") users[createLogin] = createPassw
print("created!")
logins=open("/Users/evan/Dropbox/Programming/Python/BDM Coding for
Beginners Magazine/logins.txt", "a") logins.write("" + createLogin + " "
createPassw) logins.close()
def oldUser(): login = input("Enter a login name: ") passw =
input("Enter password: ") # Check if user exists and login matches
password if login in users and users[login] == passw: print
("successful!") print ("User:", login, "accessed the system on",
time.asctime()) else: print ("doesn't exist or wrong password!")
while status != "q": status = mainMenu()
Way to link items? E.g. int() function is in builtin functions, math, and data types. It would be nice to symlink/alias/wikilink them so they are one thing in multiple locations.
# Comments ok at end of line instead of above line?
LC: "Functions that return values are sometimes called fruitful functions. In many other languages, a chunk that doesn’t return a value is called a procedure, but we will stick here with the Python way of simply calling it a function, or if we want to stress its lack of a return value, a non-fruitful function."
LC: "Although the bad_square function works, it is poorly written. We have done it here to illustrate an important rule about how variables are looked up in Python. First, Python looks at the variables that are defined as local variables in the function. We call this the local scope. If the variable name is not found in the local scope, then Python looks at the global variables, or global scope. This is exactly the case illustrated in the code above. While power is not found locally in bad_square, it does exist globally and therefore can be used in the function. But the appropriate way to write this function would be to pass power as an argument to the square function. For practice, you should rewrite the bad_squareexample to have a second parameter called power."
Term: "shadows" - when a local variable has the same name as a global variable
In general, local variables should not have the same name as any global variables.
Functions can belong to a class
Composition (of functions) Calling one function from within the body of another, or using the return value of one function as an argument to the call of another.
Can assign functions to a variable and functions can be arguments to other functions
Python Reference
Variables
Constants
Scope
Identity & Equality
Example Challenge from Python for Kids
_
Python Data Types
Numbers
Collections v
Boolean
NoneType
Type Casting
Every value in Python has exactly one datatype. Since everything is an object in Python programming, data types are actually classes and variables are instances (object) of these classes.
Mutability & Immutability
Object Checking (isinstance(), type(), __eq__, __ne__) v
Abstract Data Types
Composite Data Types
Type Annotations
Static Type Checkers
Python Data Structures
Linked lists, trees, etc?
(aka Containers)
Strings
Lists
Tuples
Dictionaries
Sets
Arrays
Stacks
Queues
JSON
Indexing & Slicing
Splitting & Joining
len()
.count()
Boolean Container Membership Operators (in and not in)
Collection Iteration v
Strings are essentially lists in Python so a lot of the functions carry over
You can store a tuple in a list, a list in a tuple, & a dictionary in a list or tuple
Python Control Flow
Conditionals
Iteration
Exception/Error Handling
Program Termination
Pause Execution
Python Quantitative Programming
Operators
Math & Science
Date & Time
Python IO
Input
Output
Files
APIs
UI
Graphics
Multimedia
Youtube-dl
Visualization & Graphs
Issues
Global and Local Scope Example from ATBS
Why doesn't declaring the variable step as global within the conditionals work - it works when step is declared first, outside the conditionals, but inside the function.
What exactly is the i in for i loops? Is it technically local? Or different in some way? The below used name variable when it was used previously. So it seems like it’s being used locally sort of.
Why does this program actual run the function mainMenu()? It seems like it just assigns the function to the variable, not actually call the function.
Way to link items? E.g. int() function is in builtin functions, math, and data types. It would be nice to symlink/alias/wikilink them so they are one thing in multiple locations.
# Comments ok at end of line instead of above line?