Evan Harmon - Memex

Python

!g Python

Meta Python

Environment

Python Installation

Installer

Manage Multiple Python Versions

Python Execution & Scripting

  • Running a program
    • python3 my_program
  • Interactive shell/Interpreter/REPL
    • You can launch a python interpreter from the command line by just typing python or python 3 for python 2 or 3 respectively
    • quit() or exit()
      • quit the shell
    • iPython
      • basically an interactive shell version of a Jupyter notebook. The basis on which Jupyter Notebook was built.
      • I think I like this as my preferred REPL now. A lot of people use it like Tom Lynch
    • bpython
  • python3
    • I like to alias python to python3 though
    • python --version
    • -c
      • 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.
  • Make a Python script run BASH commands
    • import subprocess
    • subprocess.run(['echo', 'hello'])
    • mvn = subprocess.run(['mvn', 'clean', 'install'], cwd='/Users/evan/Dropbox/Development/Neighbor Share/neighbor-share') print(mvn)
    • cwd='/Users/evan/Dropbox/Development/Neighbor Share/neighbor-share'
    • backup = subprocess.run(['ssh', 'neighborshare@neighbor-share.org', 'mv', 'neighbor-share/neighborshare-0.0.2-SNAPSHOT.jar', 'neighbor-share/neighborshare-0.0.2-SNAPSHOT.jar.bak'])
    • restart = subprocess.run(['ssh', 'neighborshare@neighbor-share.org', 'sudo', 'systemctl', 'restart', 'neighborshare.service'])
      • 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
  • argparse

Python Frameworks

Electronics & Making
Other
Quart
Masonite

Python Servers

Python Environment Variables

  • 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 IDEs

Python Functions

Declare a Function

  • def f():
  • return
    • exits function at that point
    • 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.
    • __repr__
      • def __repr__(self): return "x=" + str(self.x) + ", y=" + str(self.y)
      • 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__
        • class SomeClass(): def __init__(self, some_list): self.some_list = some_list def __str__(self): return str(self.some_list) class AnotherClass(): def __init__(self, name): self.name = name def __repr__(self): return self.name element1 = AnotherClass("element1") element2 = AnotherClass("element2") some_list = [element1, element2] some_object = SomeClass(some_list) print(some_object)
        • https://stackoverflow.com/questions/727761/python-str-and-lists
  • Custom Operator Methods
    • 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

ORM

Dot Notation

  • Use of the dot operator, ., to access functions inside a module, or to access methods and attributes of an object.

Object Checking (isinstance(), type(), __eq__, __ne__)

  • isinstance()
  • type()
    • Displays data type of given variable
  • Identity Comparison Operators v

Are python classes a subclass of Object and Type?

  • 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

Static Type Checkers

Python Data Structures

Linked lists, trees, etc?

(aka Containers)

Strings

  • Aka strs (pronounced stirs)
  • 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.
    • Tab Character
      • \t
    • Interrobang
    • Unicode
  • 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
  • Regular Expressions (Regex)
  • Collection Iteration v
  • ord() and chr()
    • ord()
      • Ordinal Value
      • string method
      • print(ord("A"))
        • 65
      • print(ord("B"))
        • 66
      • print(ord("5"))
        • 53
      • print(ord("a"))
        • 97
      • print(ord(" "))
        • 32
    • chr()
      • 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?
  • Justifying Text
    • rjust()
    • ljust()
    • center()
  • String Module (String Constants)
    - import string
    - print(string.ascii_lowercase)
    abcdefghijklmnopqrstuvwxyz
    - print(string.ascii_uppercase)
    ABCDEFGHIJKLMNOPQRSTUVWXYZ
    - print(string.digits)
    0123456789
    - print(string.punctuation)
    !"#$%&'()*+,-./:;<=>?@[]^_`{|}~
    - string.whitespace
    - E.g., if char in string.punctuation:

Lists

  • Mutable
  • Ordered
    • 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.
  • Item Assignment
    - fruit[0] = "pear"
    - fruit[-1] = "orange"
    - alist = ['a', 'b', 'c', 'd', 'e', 'f'] alist[1:3] = ['x', 'y']
    ['a', 'x', 'y', 'd', 'e', 'f']
    - alist = ['a', 'b', 'c', 'd', 'e', 'f'] alist[1:3] = []
    ['a', 'd', 'e', 'f']
    - alist = ['a', 'd', 'f'] alist[1:1] = ['b', 'c']
    ['a', 'b', 'c', 'd', 'f']
    - alist = ['a', 'b', 'c', 'd', 'f'] alist[4:4] = ['e']
    ['a', 'b', 'c', 'd', 'e', 'f']
  • Looping with Lists
    • (Or strings)
    • Item as Iterator
      • 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)
  • Tuples in Lists
    • Create grouped tuples in a list
      • list_name = [("Evan", 100), ("Cayden", 10), ("Bojangles", 4)]
    • 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
  • in and not in
  • Dictionary Initialization
    • my_dict = {}
    • my_dict = dict()
    • phonebook={'Jenny': 8168972345, 'Johnny': 7893419870}
  • .keys()
    • Lists dictionary’s keys
    • return list-like data types
    • "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
  • len(example)
    • Number of items in the set
  • union
  • intersection
  • Value in set returns boolean
    • Or not in

Arrays

  • Arrays vs Lists
    • https://stackoverflow.com/questions/176011/python-list-vs-array-when-to-use
      • 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.
  • Itertools
  • range()
  • 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.
  • with
  • 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
  • Comparison Operators
    • ==
    • !=
    • <
      • Also works for alphabetic ordering?
    • >
    • <=
    • >=
    • Chaining Comparison Operators
      • https://www.geeksforgeeks.org/chaining-comparison-operators-python/
        • 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=‘ ‘
      • print("hey!")
      • print("hey", "yourself!")
      • print("LaunchCode was founded in", 2013)
      • print("2 + 2 =", 2 + 2)
      • print("Launch" + "Code")
      • print("St. Louis\nMiami\nRhode Island\nKansas City")
    • auto adds \n character at end
  • sys.stdout
    • sys.stdout.write('message")
      • 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)

APIs

UI

  • GUI Modules
    • Tkinter
      • Usually installed with Python 3 so you can import it without pip
      • Most popular, standard GUI toolkit for Python
      • IDLE is written with Tkinter
    • PySimpleGUI
    • Kivy
    • PyperCard
    • QT for Python (PySide)
    • PyQT
      • Similar to QT for KDE, etc.
    • WxPython
    • PyGTK
      • Like Linux GTK, but being converted to PyGObject
    • Zenity
      • Simple, cross-platform module, good for simple dialogue boxes
      • But I couldn't get it working on MacOS - I think it doesn't work easily in MacOS but it pretty good across Linux and Windows.

Graphics

  • Turtle Module
    • import turtle
    • wn = turtle.Screen()
    • wn.bgcolor("lightgreen")
    • wn.setworldcoordinates(0-border, 0-border, 40 * num_bars + border, max_height + border)
    • tess = turtle.Turtle()
    • turtle_name.up()
      • pen up
      • equivalent to penup method?
    • turtle_name.down()
      • pen down
    • tess.forward(150)
    • turtle_name.backward(50)
    • tess.left(120)
    • tess.right(90)
    • turtle.setpos(60,30)
    • turtle.reset()
    • turtle.circle(50)
      • turtle.circle(50, 180)
        • semicircle
    • tess.color("blue")
      • tess.color(1,0,0)
    • tess.fillcolor("red")
    • .begin_fill
      • remember the starting point for a filled polygon
    • .end_fill
      • Close the polygon and fill with the current fill color
    • tess.pensize(3)
    • wn.exitonclick()
    • alex.speed(10)
      • 1-10 10 being fastest
      • 0 = go as fast as possible
    • alex.write("Hello")
    • wn.setworldcoordinates(0-border, 0-border, 40 * num_bars + border, max_height + border)
    • tess.stamp()
      • leaves a stamp on the canvas that remains there. Works even with pen up
    • .dot
      • leaves a dot
    • .heading
      • returns current heading
    • .position
      • returns current position
    • alex.shape("turtle")
      • turtle shapes
        • arrow, blank, circle, classic, square, triangle, turtle
    • LaunchCode Example
      • 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()
  • pyxeledit

Multimedia

  • Audio
  • Video
  • Image
    • opencv
    • simplecv
      • http://simplecv.org/
      • can use/uses opencv
      • supposedly much easier way to do opencv type stuff
      • looks very good
    • Pillow
    • LaunchCode's Image Module (not regular module)
      • import image
      • Image class
        • Create an image object
          • Via file
            • img = image.Image(“cy.png”)
          • Create empty image with all white
            • img = image.EmptyImage(100,200)
      • Pixel class
        • Pixel(20,100,50)
          • Create a new pixel with 20 red, 100 green, and 50 blue.
        • getRed()
          • r = p.getRed()
            • Return the red component intensity.
        • setRed()
          • p.setRed(100)
            • Set the red component intensity to 100.
      • w = img.getWidth()
      • h = img.getHeight()
      • p = img.getPixel(35,86)
        • column, row
      • img.setPixel(100,50,mp)
      • import image img = image.Image("luther.jpg") print(img.getWidth()) print(img.getHeight()) p = img.getPixel(45, 55) print(p.getRed(), p.getGreen(), p.getBlue())
      • import image img = image.Image("goldygopher.png") win = image.ImageWin(img.getWidth(), img.getHeight()) img.draw(win) img.setDelay(1, 15) # setDelay(0) turns off animation for row in range(img.getHeight()): for col in range(img.getWidth()): p = img.getPixel(col, row) new_red = 255 - p.getRed() new_green = 255 - p.getGreen() new_blue = 255 - p.getBlue() new_pixel = image.Pixel(new_red, new_green, new_blue) img.setPixel(col, row, new_pixel) img.draw(win) win.exitonclick()

Youtube-dl

Visualization & Graphs

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?

Sources

Automate the Boring Stuff

The Self-Taught Programmer

Head First Learn to Code

Head First Python

Python for Kids

Python Crash Course

The Python Manual Magazine

YouTube - Socratica - Python

Udacity Nanodegree

MIT Intro to Computer Science with Python

Corey Schafer - YouTube & Blog

Cheat Sheet

Inbox

  • https://python-patterns.guide/
  • zip()
  • ?maps similar indexes of multiple collections together?
  • Namespaces
  • Python Reddit API Wrapper
  • praw
    • pip install praw
  • Recursion, Memoization
  • To avoid prohibitive recursion you can use a Python’s cache functions - memoization
  • Feed-parser
  • rss
  • Sensehat
  • BeautifulSoup
  • https://www.crummy.com/software/BeautifulSoup/bs4/doc/
  • Pyautogui
    • control mouse and keyboard (covered by Al Sweigert in Automate the
    • Boring Stuff) by Al Sweigert
    • pip3 install pyautogui
  • Minecraft
    • commands
      • import mcpi.minecraft as minecraft
      • mc = minecraft.Minecraft.create()
      • mc.postToChat("Hello World!)
      • mc.player.setPosition(x, y, z)
      • mc.player.getTilePos()
      • mc.setBlock()
    • when passed two positions, will fill the gap in between (3 dimensionally
    • and volumetrically) with any block you want. The quickest and easiest
    • way to create buildings in Minecraft is by creating a cube and then
    • hollowing it out by creating a cube of air in the middle.
      • mc.setBlocks(p.x + 1, p.y, p.z + 1, p.x + 10, p.y + 5, p.z + 10, block.ICE)
    • iceman.py
      • import mcpi.minecraft as minecraft
      • import mcpi.block as block
      • mc = minecraft.Minecraft.create()
      • while True:
      • p = mc.player.getTilePos()
        get player's current position as variable p
      • mc.setBlock(p.x, p.y, p.z, block.SNOW)
    • for hit in mc.events.pollBlockHits():
    • mc.setBlock(hit.pos.x, hit.pos.y, hit.pos.z, block.ICE)
    • Make a building made of ice
      • icehouse.py
    • from mcpi.minecraft import Minecraft from mcpi import block=
    • Minecraft.create()= mc.player.getTilePos().setBlocks(p.x + 1, p.y, p.z +
    • 1,.x + 10, p.y + 5, p.z + 10,.ICE).setBlocks(p.x + 2, p.y + 1, p.z + 2,
    • p.x + 9, p.y + 4, p.z + 9,.AIR).setBlocks(p.x + 5, p.y + 1, p.z + 1, p.x
    • 6, p.y + 3, p.z + 1,.AIR) .setBlocks(p.x + 2, p.y, p.z + 2, p.x + 9,
    • p.y, p.z + 9,.WOOL.id, 14)
    • Minecraft SenseHat
      • walkingwithsteve.py
    • from mcpi.minecraft import Minecraftpyautogui as pagtimesense_hat
    • import SenseHat= SenseHat()unpress():#unpresses all the keysfor key in
    • ['s','w','a','d']:pag.keyUp(key)move(direction):#presses the correct
    • keyunpress()pag.keyDown(direction)displayArrow(c,rot):#the arrowarrow =
    • [e,e,e,c,c,e,e,e,e,e,c,c,c,c,e,e,e,c,c,c,c,c,c,e,c,c,e,c,c,e,c,c,c,e,e,c,c,e,e,c,e,e,e,c,c,e,e,e,e,e,e,c,c,e,e,e,e,e,e,c,c,e,e,e]sh.set_rotation(rot)sh.set_pixels(arrow)=
    • [255,0,0]#define the colours= [0,0,0]= [0,255,0]= [0,0,255]=
    • [#the stop
    • sign,r,r,r,r,r,r,r,,r,r,r,r,r,r,r,,r,r,r,r,r,r,r,,r,r,r,r,r,r,r,,r,r,r,r,r,r,r,,r,r,r,r,r,r,r,,r,r,r,r,r,r,r,,r,r,r,r,r,r,r]=
    • 'SSSS'True:#main loopx, y, z = sh.get_accelerometer_raw().values()x =
    • round(x, 0)y = round(y, 0)if x == -1 and abs(y) == 0 and mot != 'rrrr':
    • displayArrow(b,0)move('d')#rightmot = 'rrrr'elif x == 1 and abs(y) == 0
    • and mot != 'llll': displayArrow(b,180)move('a')#leftmot = 'llll'elif y
    • == -1 and mot != 'wwww': displayArrow(g,270)move('w')#fwdmot =
    • 'wwww'elif y == 1 and mot != 'bbbb':displayArrow(g,90)move('s')#backmot
    • = 'bbbb'elif abs(x) == 0 and abs(y) ==
    • 0:unpress()#stopsh.set_pixels(stop)mot = 'SSSS'
      • sudo apt-get install python-xlib
        • which allows use of sudo pip install pyautogui
    • can simulate keys
    • Lava game
      • lavatrap.py
    • import mcpi.minecraft as minecraftmcpi.block as blocktime import sleep=
    • minecraft.Minecraft.create().postToChat("Welcome to the Lava Trap")(3)=
    • mc.player.getTilePos().setBlocks(pos.x - 5, pos.y - 2, pos.z - 5,pos.x +
    • 5, pos.y - 2, pos.z + 5,block.STONE.id).setBlocks(pos.x - 5, pos.y - 1,
    • pos.z - 5,pos.x + 5, pos.y - 1, pos.z + 5,block.LAVA.id).setBlock(pos.x,
    • pos.y - 1, pos.z, block.DIAMOND_BLOCK.id).postToChat("Get
    • Ready").postToChat("Blocks under you will keep
    • disappearing")(3).postToChat("Go")= Falsegameover == False:p =
    • mc.player.getTilePos()mc.setBlock(p.x, p.y - 1, p.z,
    • block.OBSIDIAN.id)sleep(2)mc.setBlock(p.x, p.y - 1, p.z,
    • block.AIR.id)sleep(0.5)if p.y != pos.y:gameover = True.postToChat("Game over.")
      • Challenges
        • Make the game harder.
        • Make a better game arena, perhaps building a stadium or walls
        • around it so Steve can get out.
        • Add points to the game; each time Steve doesn’t fall in, he gets
        • a point.
        • Change the game so it starts easy but gets harder the longer you play.
        • Add a two-player (or even multiplayer!) option.
    • TNT Run!
    • Minecraft Sources
  • NLTK
  • Computer Programming for Everybody Essay
  • PyTorch
  • Scikit-learn
Python
Interactive graph
On this page
Python
Meta Python
Python Language
Python Syntax & Reserved Keywords
Python Linting, Formatting, & Conventions
Python Patterns, Principles & Best Practice
Python Documentation & Comments
Python Security
Python Debugging & Troubleshooting
Python Testing
Python Logging
Environment
Python Installation
Manage Multiple Python Versions
Python Execution & Scripting
Python Scripting
Python Dependencies, Packages, Libraries, Modules, & Structure
Python Frameworks
Web app
Flask
Django
Tornado
API
FastApi
Electronics & Making
Other
Zappa
Pyramid
Quart
Bottle
Web2py
Masonite
Hug
CherryPy
Python Servers
Python Environment Variables
Python IDEs
Python Functions
Declare a Function
Main Function?
Docstrings
Types of Functions
Decorators #issue
Lambda Functions
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.
Object-Oriented Python
Objects
Classes
Composition
ORM
Dot Notation
Object Checking (isinstance(), type(), __eq__, __ne__)
Are python classes a subclass of Object and Type?
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
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?
Sources
Automate the Boring Stuff
The Self-Taught Programmer
TalkPython Training
Head First Learn to Code
Head First Python
Python for Kids
Python Crash Course
The Python Manual Magazine
YouTube - Socratica - Python
https://www.fullstackpython.com/
Udacity Nanodegree
MIT Intro to Computer Science with Python
https://gto76.github.io/python-cheatsheet/
Corey Schafer - YouTube & Blog
Cheat Sheet
Inbox