python programming: lecture 4 object oriented programmingcis192/fall2014/files/lec4.pdf · multiple...

93
Python Programming: Lecture 4 Object Oriented Programming Lili Dworkin University of Pennsylvania October 3, 2014

Upload: others

Post on 06-Jun-2020

7 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Python Programming: Lecture 4Object Oriented Programming

Lili Dworkin

University of Pennsylvania

October 3, 2014

Page 2: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Good Question from Last Week

>>> def foo(a, b, c):

... print a, b, c

...

>>> foo(1, 2, 3)

1 2 3

>>> l = [1, 2, 3]

>>> foo(*l)

1 2 3

>>> l.append(4)

>>> foo(*l)

TypeError: foo() takes exactly 3 arguments (4 given)

Page 3: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

Write a function that takes a variable number of keywordarguments, and prints out a comma separated list of the argumentvalues. Hint: use join and d.values(). An example:

>>> foo(cat=1, dog=2)

1, 2

Page 4: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

Write a function that takes a variable number of keywordarguments, and prints out a comma separated list of the argumentvalues.

>>> def foo(**kwargs):

... print ', '.join(map(str, kwargs.values()))

I Use two stars (**) for keyword arguments

I .join() is called on the separator/delimiter object

I kwargs is a dictionary

I kwargs.values() is a list of the dictionary values

I .join() only works on lists of strings

Page 5: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

>>> def foo(**kwargs):

... print ', '.join(map(str, kwargs.values()))

...

>>> foo(cat=1, dog=2)

2, 1

>>> d = {'cat':1, 'dog':2, 'canary':500}>>> foo(**d)

2, 500, 1

Page 6: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

What about a function that takes a variable number of positionalarguments and prints them out in a space separated list?

Page 7: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

What about a function that takes a variable number of positionalarguments and prints them out in a space separated list?

>>> def foo(*args):

... print ' '.join(map(str, args))

...

>>> foo('cat', 5, [True, False])

cat 5 [True, False]

Page 8: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

What does the following print?

>>> l = []

>>> def foo(data=l):

... print data

...

>>> l = ['a']>>> foo()

Page 9: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

>>> l = []

>>> def foo(data=l):

...

Explicit binding!

Page 10: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

>>> l = []

>>> def foo(data=l):

...

>>> l = ['a']

Page 11: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

What about the following?

>>> def outer(l):

... def inner():

... return l

... return inner

...

>>> l = ['a']>>> f = outer(l)

>>> f()

['a']>>> l.append('b')>>> f()

?

Page 12: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

What about the following?

>>> def outer(l):

... def inner():

... return l

... return inner

...

>>> l = ['a']>>> f = outer(l)

>>> f()

['a']>>> l.append('b')>>> f()

['a', 'b']

I It’s a closure, but we enclosed a mutable object

I (This was a question asked last week)

Page 13: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

Using map and filter (and the is even function defined in lecture),write an expression equivalent to

>>> [str(x) for x in [1,2,3] if is_even(x)]

Page 14: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

Using map and filter (and the is even function defined in lecture),write an expression equivalent to

>>> [str(x) for x in [1,2,3] if is_even(x)]

>>> map(str, filter(is_even, [1,2,3]))

I Do not use parentheses when working with function objects!(e.g. str() or str(x))

I In this case, call filter first, because is_even won’t workon string objects

Page 15: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

Fill in the ... below. custom_sum(x) should return a function thattakes a list of integers, computes a sum, and adds x to it.

def custom_sum(x):

def my_sum(l):

return ...

return ...

>>> s = custom_sum(10)

>>> s([1,2,3])

16

Page 16: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

Fill in the ... below. custom_sum should return a function thattakes a list of integers, computes a sum, and adds x to it.

def custom_sum(x):

def my_sum(l):

return sum(l) + x

return my_sum

I Because custom_sum returns a function, you should knowthat the last line should be return my_sum (no parentheses!)

Page 17: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

What about this? foo should return a function that takes avariable number of positional arguments, and returns a list where xis the first element.

def foo(x):

def bar(...):

return ...

return ...

Page 18: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

What about this? foo should return a function that takes avariable number of positional arguments, and returns a list where xis the first element.

def foo(x):

def bar(*args):

return [x] + list(args)

return bar

Page 19: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

Sort a list of numbers so that the even numbers come first. Note:In Python, False < True

Page 20: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Last Week’s Quiz

Sort a list of numbers so that the even numbers come first. Note:In Python, False < True

>>> sorted(l, key=is_even, reverse=True)

>>> sorted(l, key=lambda x: not is_even(x))

I Note the use of parentheses :)

Page 21: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Classes

class Point:

def __init__(self, x, y): # constructor

self.x = x # data attribute

self.y = y

def norm(self): # method

return math.sqrt(self.x ** 2 + self.y ** 2)

Page 22: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Construction

>>> p = Point(1,2)

I Calls the __init__ method

I Note that we only passed in two arguments

I self is a reference to the object instance itself

I When you call Point(), Python creates an object for you,and passes it as the first parameter to the __init__ method

Page 23: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Attributes and Methods

Everything is (basically) public:

>>> p = Point(3,4)

>>> p.x # get attribute

3

>>> p.x = 3 # set attribute

Both of the following will call a method:

>>> Point.norm(p)

5.0

>>> p.norm()

5.0

We will always use the second syntax. Note how this syntax“automatically” passes p in as the self parameter.

Page 24: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

More About self

I Methods must take at least one argument (called self)

I Attributes and other methods are acccessed through self

def print_norm(self):

print "||(%d, %d)|| = %.1f" %

(self.x, self.y, self.norm())

>>> p.print_norm()

||(3, 4)|| = 5.0

Page 25: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Data vs. Class Attributes

I Java’s instance variables = Python’s data attributes

I Java’s static variables = Python’s class attributes

class Point:

count = 0 # class attribute

def __init__(self, x, y):

self.x = x

self.y = y

Point.count += 1

Page 26: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Data vs. Class Attributes

Class attributes can be accessed directly through the class, ratherthan through an instance (though that works too):

>>> Point.count

0

>>> p = Point(1,2)

>>> Point.count

1

>>> p.count

1

Page 27: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

getattr

The following are equivalent:

>>> p = Point(1,2)

>>> p.x

1

>>> getattr(p, 'x')1

getattr takes as input 1) either an instance or a class and 2) thestring name of an attribute or method

Page 28: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

getattr

Difference between passing a class vs. instance:

>>> f = getattr(Point, 'norm')>>> f(p)

5.0

>>> g = getattr(p, 'norm')>>> g()

5.0

Page 29: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

getattr

Can be used on builtins!

>>> f = getattr(str, 'isalpha')>>> f('a')True

>>> l = [1,2]

>>> g = getattr(l, 'append')>>> g(3)

>>> l

[1, 2, 3]

Page 30: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

getattr

Use case: decision of which method to use is decided at runtime.

class Foo:

def method1(self):

print "Calling method1."

def method2(self):

print "Calling method2."

def call_method(foo, num):

f = getattr(foo, "method%d" % num)

f()

>>> foo = Foo()

>>> call_method(foo, 2)

Calling method2.

Page 31: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Inheritance

class Animal(object): # new-style object

def __init__(self, name):

self.name = name

class Cat(Animal):

pass

>>> cat = Cat('Missy')>>> cat.name

'Missy'

Automatically called parent’s __init__.

Page 32: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Inheritance

__init__ is optional, but if you define it, you must remember tocall the parent’s __init__. This is true in general when extendingthe behavior of the parent.

class Cat(Animal):

def __init__(self, name, breed=None):

Animal.__init__(self, name) # don't forget!

self.breed = breed

>>> cat = Cat("Missy", "Persian")

>>> cat.name

'Missy'>>> cat.breed

'Persian'

Page 33: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Inheritance

The previous syntax was pretty ugly – we had to remember thatour superclass was named “Animal.” This is better:

class Cat(Animal):

def __init__(self, name, breed=None):

super(Cat, self).__init__()

self.breed = breed

This also works with multiple inheritance, as we will see shortly.

Page 34: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Inheritance

class Animal(object):

def talk(self):

return 'I say '

class Cat(Animal):

def talk(self):

print super(Cat, self).talk() + 'meow.'

class Dog(Animal):

def talk(self):

print super(Dog, self).talk() + 'bark.'

>>> cat.talk()

I say meow.

>>> dog.talk()

I say bark.

Page 35: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Multiple Inheritance

I A class can inherit from multiple base classes:

class Subclass(Base1, Base2, Base3 ...)

I Resolution rule: depth-first, left-to-right

I If an attribute or method is not found in Subclass, it issearched for in Base1, then in the base classes of Base1, andif not found there, it is searched for in Base2, and so on.

Page 36: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Multiple Inheritance

class A(object):

def foo(self):

print 'Foo!'

class B(object):

def foo(self):

print 'Foo?'

def bar(self):

print 'Bar!'

class C(A,B):

def foobar(self): # what will this print?

super(C, self).foo()

super(C, self).bar()

Page 37: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Multiple Inheritance

>>> c = C()

>>> c.foobar()

Foo!

Bar!

We found the foo method in class A (and stopped there), andthen we found the bar method in class B.

Page 38: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

A language mechanism for restricting access to some of theobject’s components.

I Python doesn’t really do encapsulation.

I No such thing as private or protected members. **

I “We’re all adults here.” – Guido

I ** Well, kind of ...

Page 39: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

I Use a single leading underscore (_var) as a weak “internaluse indicator.”

I from module import * does not import objects whosename starts with an underscore.

Page 40: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

Use two leading underscores to indicate a private method orattribute:

class Private:

def __init__(self, secret):

self.__secret = secret

def __keep_secret(self):

return self.__secret

def release_secret(self):

return self.__secret

Page 41: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

>>> p = Private('I am Iron Man.')>>> p.__secret

AttributeError

>>> p.__keep_secret()

AttributeError

>>> p.release_secret()

'I am Iron Man.'

This looks a lot like “real” privacy, but ...

Page 42: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

I Behind the scenes, Python changes the name of __var to_ClassName__var.

I So __var doesn’t exist, and can’t be accessed.

I But _ClassName__var still works.

>>> p = Private('I am Iron Man.')>>> p._Private__secret

'I am Iron Man.'>>> p._Private__keep_secret()

'I am Iron Man.'

Page 43: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

This seems silly – what’s the point?

I To ensure that subclasses don’t accidentally override theprivate methods and attributes of their superclasses.

I Not designed to prevent deliberate access from outside.

Page 44: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

class Foo(object):

def __init__(self):

self.__baz = 42

def foo(self):

print self.__baz

class Bar(Foo):

def __init__(self):

super(Bar, self).__init__()

self.__baz = 21

def bar(self):

print self.__baz

Page 45: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

>>> x = Bar()

>>> x.foo()

# ?

>>> x.bar()

# ?

Page 46: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

>>> x = Bar()

>>> x.foo()

42

>>> x.bar()

21

Page 47: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

What really happened:

class Foo(object):

def __init__(self):

self._Foo__baz = 42

def foo(self):

print self._Foo__baz

class Bar(Foo):

def __init__(self):

super(Bar, self).__init__()

self._Bar__baz = 21

def bar(self):

print self._Bar__baz

Page 48: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

class Mapping:

def __init__(self, items):

self.items_list = []

self.update(items)

def update(self, items):

for item in items:

self.items_list.append(item)

class MappingSubclass(Mapping):

def update(self, keys, values):

for item in zip(keys, values):

self.items_list.append(item)

Page 49: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

>>> map = Mapping([1,2,3])

>>> map.items_list

[1, 2, 3]

>>> map = MappingSubclass([1,2,3])

# What will happen?

Page 50: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

>>> map = Mapping([1,2,3])

>>> map.items_list

[1, 2, 3]

>>> map = MappingSubclass([1,2,3])

TypeError: update() takes exactly 3 arguments (2

given)

The base __init__ tried to call the update() method of thesubclass, rather than the base.

Page 51: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Encapsulation

class Mapping:

def __init__(self, items):

self.items_list = []

self.__update(items)

def update(self, items):

for item in items:

self.items_list.append(item)

__update = update # private copy

class MappingSubclass(Mapping):

def update(self, keys, values):

...

Now we call the base’s version of update.

Page 52: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Magic Methods

What are they?!

I Special kinds of class methods (like __init__) that areprefixed and suffixed with two underscores.

I Provide a easy way to make our own classes behave likebuilt-in types.

I Essentially, we will redefine the behavior of Python’s built-inoperators, like “==” and “len” and “in.”

I Great tutorial:http://www.rafekettler.com/magicmethods.html

Page 53: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Magic Methods

If you want ... Then define ...

print x __repr__

x == y __eq__

x > y __cmp__

x + y __add__

len(x) __len__

item in x __contains__

for item in x __iter__

x[key] __getitem__

Page 54: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Magic Methods

I Non-traditional kind of polymorphismI e.g. we can use “+” on any type that implements __add__

I Generally, we shouldn’t check type, but just try to use themethod we want

I If the method is implemented, it gets executed, regardless ofthe object’s type

I In some sense, the actual type doesn’t actually matter

I Duck Typing: an object’s methods, rather than its type,determine its valid semantics

Page 55: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Printing

>>> p = Point(1,2)

>>> print p

<__main__.Pair instance at 0x105c95d88>

Need to define __repr__:

def __repr__(self):

return "(%d, %d)" % (self.x, self.y)

>>> print p

(3, 4)

Page 56: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Hashing

>>> p = Point(1,2)

>>> d = {}

>>> d[p] = "Hi"

TypeError: unhashable instance

Need to define __hash__:

def __hash__(self):

return hash((self.x,self.y))

>>> p = Point(1,2)

>>> d[p] = "Hi"

>>> d.keys()

[(1, 2)]

Page 57: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Equality

>>> Point(1,2) == Point(1,2)

False

Need to define __eq__:

def __eq__(self, other):

return self.x == other.x and \

self.y == other.y

>>> Point(1,2) == Point(1,2)

True

Page 58: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Addition

>>> Point(1,2) + Point(1,2)

TypeError

Need to define __add__:

def __add__(self, other):

return Point(self.x + other.x,

self.y + other.y)

>>> Point(1,2) + Point(3,4)

(4, 6)

Page 59: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Protocols

I All the stuff we’ve seen so far is about getting your class tobehave like a number.

I What about a list? A string? A file?!

I Python supports protocols, which are similar to interfaces:they define a set of (magic) methods you need to support toimplement that protocol.

I In Python, protocols are informal and do not require explicitdeclarations.

Page 60: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Protocols

I ComparsionI Most like what we’ve seen so farI Need __eq__, __cmp__

I ContainersI Things like lists and dictionariesI Need __len__, __getitem__, __setitem__, __contains__

I Iterators – will see next week!

I Context Managers (like files) – will see later

I Descriptors – kind of confusing and may never see

Page 61: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Containers

class Buckets(object):

def __init__(self, red, blue):

self.red = red

self.blue = blue

def __len__(self):

return len(self.red) + len(self.blue)

def __getitem__(self, key):

if key in self.red:

return 'red'elif key in self.blue:

return 'blue'

...

Page 62: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Containers

...

def __setitem__(self, key, value):

if key in self.red and value == 'blue':self.red.remove(key)

self.blue.append(key)

elif key in self.blue and value == 'red':self.blue.remove(key)

self.red.append(key)

def __contains__(self, item):

return item in self.red or item in self.blue

Page 63: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Containers

>>> b = Buckets([1,2], [3,4])

>>> len(b)

4

>>> b[1]

'red'>>> b[1] = 'blue'>>> b[1]

'blue'>>> 4 in b

True

Page 64: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Decorators

A few basic OOP things we haven’t covered yet:

I Getters / Setters

I Static methods

To do so, we need to take a detour and talk about decorators.

Page 65: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Decorators

Decorators are functions that:

I Take a function f as input

I Define a new (nested) function new_f that calls f, but alsodoes other stuff before and/or after

I Return new_f

Page 66: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Debug Decorator

def debug(f):

def new_f(*args):

print "About to call %s." % (f.__name__)

result = f(*args)

print "Finished calling %s." % (f.__name__)

return result

return new_f

Page 67: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Debug Decorator

>>> debug_sum = debug(sum)

>>> debug_sum([1,2,3])

About to call sum.

Finished calling sum.

6

Page 68: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Debug Decorator

I What if we are defining a new function g, and we always wantit to have this debug behavior?

I After defining g, we could overwrite it with g = debug(g).

I Or we have the following syntactic sugar:

@debug

def g():

print "Running."

>>> g()

About to call g.

Running.

Finished calling g.

Page 69: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Sorting Decorator

def sort(f):

def new_f(*args):

return sorted(f(*args))

return new_f

@sort

def random_list(n):

return [random.randint(0,100) \

for _ in range(n)]

>>> random_list(5)

[14, 30, 43, 44, 90]

Page 70: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Counting Decorator

def count(f):

c = [0] # can do things before defining new_f

def new_f(*args):

c[0] += 1

return (c[0], f(*args))

return new_f

@count

def id(x):

return x

>>> id(5)

(1, 5)

>>> id(5)

(2, 5)

Page 71: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Function List Decorator

functions = []

def add_func(f):

results.append(f)

return f # don't have to change f

@add_func

def id(x):

return x

>>> functions

[<function id at 0x10f5a2b18>]

Note that the function id will only get added to the list once nomatter how many times we call it.

Page 72: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Parameterized Decorators

def make_decorator(s):

def decorator(f):

def new_f(*args):

print s

return f(*args)

return new_f

return decorator

@make_decorator('foo')def id1(x):

return x

@make_decorator('bar')def id2(x):

return x

Page 73: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Properties

Getting and setting attributes is pretty easy:

class Foo(object):

def __init__(self, x):

self.x = x

>>> f.x

5

>>> f.x = 10

>>> f.x

10

Page 74: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Properties

What if we want more control?

class Foo(object):

def __init__(self, x):

self._x = x

@property

def x(self):

print "x is being accessed."

return self._x

@x.setter

def x(self, new_x):

print "x is being set."

self._x = x

Page 75: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Properties

>>> f = Foo(5)

>>> f.x

x is being accessed.

5

>>> f.x = 10

x is being set.

>>> f.x

x is being accessed.

10

Page 76: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Properties

Which names have to match?

class Foo(object):

def __init__(self, i):

self._eep = i

@property

def data(self):

print "eep is being accessed."

return self._eep

@data.setter

def data(self, new_eep):

self._eep = new_eep

Page 77: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Properties

>>> f = Foo(5)

>>> f.data # note!

eep is being accessed.

5

What happens here?

>>> f._eep

Page 78: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Properties

What happens here?

>>> f._eep

5

Page 79: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Properties

Some use-cases:

I Lazy-load data upon accessing

@property

def x(self):

if not x:

# execute code to get x

return x

I Validation upon setting

@x.setter

def x(self, new_x):

if valid(new_x):

self._x = new_x

else:

raise Exception

Page 80: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Class and Static Methods

I Class and static methods are associated with a class object,rather than an instance object.

class ClassName:

@classmethod / @staticmethod

def foo(...):

pass

>>> ClassName.foo() # didn't create an instance

I The difference is that a class method must have a reference toa class object as the first parameter, whereas a static methodcan have no parameters at all.

Page 81: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Class and Static Methods

class Date(object):

def __init__(self, day=0, month=0, year=0):

self.day = day

self.month = month

self.year = year

Page 82: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Class and Static Methods

Goal: convert a string ’mm-dd-yyyy’ to a Date instance.

month, day, year = map(int, s.split('-'))date1 = Date(day, month, year)

To automate this process:

@classmethod

def from_string(cls, s):

# cls refers the Date class itself

month, day, year = map(int, s.split('-'))return cls(day, month, year)

>>> d = Date.from_string('02-10-2014')

d is now an instance of Date.

Page 83: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Class and Static Methods

Goal: validate a date string

@staticmethod

def is_valid(s):

month, day, year = map(int, s.split('-'))return day <= 31 and month <= 12 and \

year <= 3999

>>> Date.is_valid('02-10-2014')True

Didn’t need a reference to the Date class here.

Page 84: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Live Quiz!

Use getattr to write code equivalent to ’4’.isdigit().

Page 85: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Live Quiz!

Use getattr to write code equivalent to ’4’.isdigit().

>>> f = getattr('4', 'isdigit')>>> f()

True

Page 86: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Live Quiz!

If we have some class Truck, how can we call the init method ofits superclass?

Page 87: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Live Quiz!

If we have some class Truck, how can we call the init method ofits superclass?

super(Truck, self).__init__()

Page 88: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Live Quiz!

If we have a class Penguin with a private method __happy_feet,how can we access this method on an instance called Joe?

Page 89: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Live Quiz!

If we have a class Penguin with a private method __happy_feet,how can we access this method on an instance called Joe?

>>> Joe._Penguin__happy_feet()

Page 90: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Live Quiz!

What is the following “syntactic sugar” for?

@decorator

def function(x):

...

Page 91: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Live Quiz!

What is the following “syntactic sugar” for?

@decorator

def function(x):

...

>>> function = decorator(function)

Page 92: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Live Quiz!

Using a propery, ensure than an attribute called age is onlyupdated if the new value is greater than the old value.

Page 93: Python Programming: Lecture 4 Object Oriented Programmingcis192/fall2014/files/lec4.pdf · Multiple Inheritance I A class can inherit from multiple base classes: classSubclass(Base1,

Live Quiz!

Using a propery, ensure than an attribute called age is onlyupdated if the new value is greater than the old value.

@age.setter

def age(self, new_age):

if new_age > self._age:

self._age = new_age