Some of this week's topics are covered in Introducing Python:
Chapter 7. Tuples and Lists
Lists
Create a List with a Comprehension
Chapter 8. Dictionaries and Sets
Dictionaries
Dictionary Comprehensions
Sets
Set Comprehensions
Chapter 10. Object and Classes
Attribute Types
Class and Object Attributes
Method Types
Class Methods
Static Methods
Duck Typing
Magic Methods
Here are some additional notes.
In Python, every class is itself an object. For example, let's
revisit the Point
class from the last lecture:
class Point: def __init__(self, x, y): self.x = x self.y = y >>> Point <class '__main__.Point'>
This is how Python prints out a class. It is an object like any other. For example, we can put it into a variable:
>>> xyz = Point >>> xyz <class '__main__.Point'>
Let's
look at an instance of the Point
class:
>>> p <__main__.Point object at 0x7fc34f4107d0> >>> type(p) <class '__main__.Point'>
The type() function returns the type of any object. In an object-oriented language such as Python, all types are classes, so type() reveals an object's class. We can confirm that type(p) is the class object itself:
>>> type(p) is Point True
More generally, we can use Python's isinstance() function to check whether an object is an instance of a class or any of its subclasses. For example, in the last lecture, we defined a class Queue and a subclass AvgQueue that extends Queue. Suppose that we create an instance of AvgQueue:
>>> q = AvgQueue()
Now q is an AvgQueue, and is also a Queue, because every AvgQueue is a Queue with extra attributes. We can verify this using isinstance():
>>> isinstance(q, AvgQueue) True >>> isinstance(q, Queue) True
Because a class is an object, we can assign attributes to it. For example:
>>> Point.abc = 7 >>> print(Point.abc + 1) 8
Class attributes are distinct from instance attributes. Each instance of the Point class has its own values of x and y, but there is only one value of the abc attribute, shared by all Point instances.
We might use a class attribute to store a constant instance of a class, for example:
>>> Point.origin = Point(0, 0)
As another example, suppose that we have a Student class, and each student has its own integer ID. We could use a class attribute to store the next ID to be assigned:
class Student: next_id = 0 def __init__(self, name): self.name = name self.id = Student.next_id Student.next_id += 1
Notice that we can initialize a class attribute inside a class definition. Python will initialize this attribute only once, as it reads the class definition - not every time it creates a new instance of a class.
We may also define methods that belong to a class but do not run on any particular instance of the class. These are called static methods.
For example, in the Student class above we could add a method that adds 100 to the next_id counter. Perhaps we'd like to do this at the beginning of each new semester, so that students who begin in different semesters have ids that are not too close:
class Student: … def new_semester(): Student.next_id += 100
Notice that a static method does not take self as an argument, since it does not run on any instance of the class. We can invoke it through the class itself:
Student.new_semester();
Another common use of static methods is to provide various ways to construct an object. For example:
class Point: … def random(): # construct a random Point return Point(randint(-100, 100), randint(-100, 100))
See the Introducing Python book for an introduction to list comprehensions. Here are some useful examples:
Adding 1 to each element in a list:
m = [i + 1 for i in l]
Generating a list of all perfect squares from 1 to 400:
squares = [i * i for i in irange(1, 20)]
A solution to Project Euler's Problem 1 (find the sum of all the multiples of 3 or 5 below 1000):
sum([i for i in range(1000) if i % 3 == 0 or i % 5 == 0])
A function that builds a nested list representing a matrix of zeroes:
def empty(rows, cols): return [cols * [0] for r in range(rows)]
A function that builds a table that holds the value (2 * i + j) for all values 0 ≤ i, j ≤ 10:
def table(): return [[2 * i + j for j in range(11)] for i in range(11)]
Finding all triples of integers (a, b, c) such that a2 + b2 = c2, with 0 ≤ a < b < c ≤ 20:
[(a, b, c) for c in range(21) for b in range(c) for a in range(b) if a * a + b * b == c * c]
As an example of a set comprehension, we can construct the set of all numbers that are the product of two single-digit integers:
{ a * b for a in range(1, 10) for b in range(1, 10) }
As an example of a dictionary comprehension, here is a function that flips a dictionary, i.e. inverts the keys and values:
def flip(d): return { val : key for key, val in d.items() }