Python Programming

Lecture 10 OOP (2), File, Test

10.1 Multiple Inheritance

  • Multiple inheritance


class Person:
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex
        
    def print_title(self):
        if self.sex == "male":
            print("man")
        elif self.sex == "female":
            print("woman")               

class Child(Person):                
    def print_title(self):
        if self.sex == "male":
            print("boy")
        elif self.sex == "female":
            print("girl")
            
class Baby(Child):
    pass
    

            
May = Baby("May","female")
May.print_title()               

girl
  • Diamond Problem (钻石继承)


class Animal():
    def __init__(self):
        print('animal')

class Dog(Animal):
    def __init__(self):
        Animal.__init__(self)
        print('dog')

class Cat(Animal):
    def __init__(self):
        Animal.__init__(self)
        print('cat')

class Husky(Dog, Cat):
    def __init__(self):
        Dog.__init__(self)
        Cat.__init__(self)
        print('husky')     



my_dog=Husky()

#output

animal
dog
animal
cat
husky

class Animal():
    def __init__(self):
        print('animal')

class Dog(Animal):
    def __init__(self):
        super().__init__()
        print('dog')

class Cat(Animal):
    def __init__(self):
        super().__init__()
        print('cat')

class Husky(Dog, Cat):
    def __init__(self):
        super().__init__()
        print('husky')     

my_dog=Husky()

my_dog=Husky()

#output

animal
cat
dog
husky

class Animal():
    def __init__(self, name):
        self.name = name

class Dog():
    def __init__(self, name):
        super().__init__(name)

class Husky(Dog, Animal):
    def __init__(self, name):
        super().__init__(name)      

print(Husky.__mro__)
#output
(<class '__main__.Husky'>, 
<class '__main__.Dog'>, 
<class '__main__.Animal'>, 
<class 'object'>)

class Animal(): 
    pass
class Dog(Animal):
    pass
class Cat(Animal):
    pass
class X(Dog, Cat):
    pass      

print(X.__mro__)

#output
(<class '__main__.Husky'>, 
<class '__main__.Dog'>, 
<class '__main__.Cat'>,
<class '__main__.Animal'>, 
<class 'object'>)

class Animal():
    pass
class Dog(Animal):
    pass
class Cat(Animal):
    pass
class Husky(Dog):
    pass
class Persian(Cat):
    pass
class X(Husky, Persian):
    pass      

print(X.__mro__)

#output
(<class '__main__.X'>, <class '__main__.Husky'>, 
<class '__main__.Dog'>, <class '__main__.Persian'>, 
<class '__main__.Cat'>, <class '__main__.Animal'>, 
<class 'object'>)

class Animal():
    pass
class Dog(Animal):
    pass
class Cat(Animal):
    pass
class Husky(Dog, Cat):
    pass
class Persian(Dog, Cat):
    pass
class X(Husky, Persian):
    pass      

print(X.__mro__)

(<class '__main__.X'>, <class '__main__.Husky'>, 
<class '__main__.Persian'>, <class '__main__.Dog'>, 
<class '__main__.Cat'>, <class '__main__.Animal'>, 
<class 'object'>)

Topological Sorting (C3)


class Animal():
    pass
class Dog(Animal):
    pass
class Cat(Animal):
    pass
class Husky(Dog, Cat):
    pass
class Persian(Cat, Dog):
    pass
class X(Husky, Persian):
    pass      

print(X.__mro__)
# Error

class Animal():
    pass
class Dog(Animal):
    pass
class X(Animal, Dog):
    pass
print(X.__mro__)
# Error

如果你一定要秀一波操作

MixIn Inheritance


class Animal():
    pass

class EatMixIn():
    def eat(self):
        print(self.name +" is eating.")
class RunMixIn():
    def run(self):
        print(self.name +" is running.") 

class Dog(Animal):
    def __init__(self, name):
        self.name = name

class Cat(Animal):
    def __init__(self, name):
        self.name = name 

class Husky(Dog, EatMixIn, RunMixIn):
    def __init__(self, name):
        super().__init__(name)

class Persian(Cat, EatMixIn, RunMixIn):
    def __init__(self, name):
        super().__init__(name)

x = Husky("Willie")
y = Persian("Coco")
x.eat() # Willie is eating.
x.run() # Willie is running.
y.eat() # Coco is eating.
y.run() # Coco is running.   

10.2 Special Methods

  • Private Attributes and methods


class Student:
    def __init__(self, name, score):
        self.__name = name
        self.__score = score

    def __show_score(self):
        print(self.__score)

    def print_score(self):
        print('%s: %s' % (self.__name, self.__score))  

bart = Student('Bart Simpson', 59)
bart.print_score()

print(bart._Student__name) #correct
bart._Student__show_score() #correct

print(bart.__name) #error
bart.__show_score() #error
  • The precise definition of dir() is that it lists the methods and attributes of a Python object.


>>> stuff = list()
>>> dir(stuff)
['__add__', '__class__', '__contains__', '__delattr__',
'__delitem__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__getitem__',
'__gt__', '__hash__', '__iadd__', '__imul__', '__init__',
'__iter__', '__le__', '__len__', '__lt__', '__mul__',
'__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__reversed__', '__rmul__', '__setattr__',
'__setitem__', '__sizeof__', '__str__', '__subclasshook__',
'append', 'clear', 'copy', 'count', 'extend', 'index',
'insert', 'pop', 'remove', 'reverse', 'sort']
  • Everything in Python is an object.


stuff = list()
stuff.append('python')
stuff.append('chuck')
stuff.sort()
print (stuff[0])

print (stuff.__getitem__(0))
print (list.__getitem__(stuff,0))

chuck
chuck
chuck
  • Actually, the class you create inherits the ``object'' class.

  • Classes can intercept Python Operators


class Dog():
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __str__(self):
        return "Dog's name is %s." % self.name  


my_dog = Dog('willie', 6)
print(dir(my_dog))
#output
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__',
 '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', 
 '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
  '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 
  'age', 'name']
  • __str__


class Dog():
    def __init__(self, name, age):
        self.name = name
        self.age = age

my_dog = Dog('willie', 6)
print(my_dog)
#output
<__main__.Dog object at 0x053A3750>

class Dog():
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __str__(self):
        return "Dog's name is %s." % self.name  

my_dog = Dog('willie', 6)
print(my_dog)
#output
Dog's name is willie.
  • __add__


class Dog():
    def __init__(self, name, age):
        self.name = name
        self.age = age

my_dog = Dog('willie', 6)

print(my_dog.name +' your_dog')
#output
willie your_dog

class Dog():
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __add__(self, other):
        return self.name + other

my_dog = Dog('willie', 6)
x = my_dog +' your_dog' 

print(x)

#output
willie your_dog

built-in Attributes

  • __dict__


class Dog():
    def __init__(self, name, age):
        self.name = name
        self.age = age

my_dog = Dog('willie', 6)
print(my_dog.__dict__) # attributes of instances
print(Dog.__dict__) # attributes of classes
#output
{'name': 'willie', 'age': 6} 
{'__module__': '__main__', 
'__init__': <function Dog.__init__ at 0x0000029EA1277B70>, 
'__dict__': <attribute '__dict__' of 'Dog' objects>, 
'__weakref__': <attribute '__weakref__' of 'Dog' objects>, 
'__doc__': None}
  • __doc__, __name__, __module__, __bases__


class Dog():
    "This is about dog class."
    def __init__(self, name, age):
        self.name = name
        self.age = age

print(Dog.__doc__)
print(Dog.__name__)
print(Dog.__module__)
print(Dog.__bases__)
#output
This is about dog class.
Dog
__main__
(<class 'object'>,)

class Dog():
    "This is about dog class."
    def __init__(self, name, age):
        self.name = name
        self.age = age
class Husky(Dog):
    pass

print(Husky.__bases__)
#output
(<class '__main__.Dog'>,)
  • Three Features of OOP

    Encapsulation, inheritance, polymorphism

  • Everything in Python is object.

  • Process-oriented programming (POP)

    Object-oriented Programming (OOP)

10.3 File

Reading from a File

  • pi_digits.txt


3.1415926535
8979323846
2643383279

with open('pi_digits.txt') as file_object:
    contents = file_object.read() # string
    print(contents.rstrip())

File Path

  • relative path


with open('text_files/filename.txt') as file_object: # Linux or OSX
with open('text_files\filename.txt') as file_object: # Windows
  • absolute path


file_path = '/home/ehmatthes/other_files/text_files/filename.txt'
with open(file_path) as file_object: # Linux or OSX
file_path = r'C:\Users\ehmatthes\other_files\text_files\filename.txt'
with open(file_path) as file_object: # Windows
  • Please add "r" if you use Windows.

Reading Line by Line


filename = 'pi_digits.txt'
with open(filename) as file_object:
    for line in file_object:
        print(line)

3.1415926535

8979323846

2643383279


filename = 'pi_digits.txt'
with open(filename) as file_object:
    for line in file_object:
        print(line.rstrip())

3.1415926535
8979323846
2643383279
  • Making a List of Lines from a File


filename = 'pi_digits.txt'

with open(filename) as file_object:
    lines = file_object.readlines() #List

for line in lines:
    print(line.rstrip())
  • Working with a File’s Contents


filename = 'pi_digits.txt'

with open(filename) as file_object:
    lines = file_object.readlines() # list read() works here

pi_string = ''
for line in lines:
    pi_string += line.rstrip()
print(pi_string)
print(len(pi_string))

3.141592653589793238462643383279 # string
32

Writing to a File


filename = 'programming.txt'

with open(filename, 'w') as file_object:
    file_object.write("I love programming.")
  • The second argument, 'w', tells Python that we want to open the file in write mode. You can open a file 198 Chapter 10 in read mode ('r'), write mode ('w'), append mode ('a'), or a mode that allows you to read and write to the file ('r+'). If you omit the mode argument, Python opens the file in read-only mode by default.

  • Python can only write strings to a text file. If you want to store numerical data in a text file, you’ll have to convert the data to string format first using the str() function.

  • Writing Multiple Lines


filename = 'programming.txt'
with open(filename, 'w') as file_object:
    file_object.write("I love programming.")
    file_object.write("I love creating new games.")

I love programming.I love creating new games.   

filename = 'programming.txt'
with open(filename, 'w') as file_object:
    file_object.write("I love programming.\n")
    file_object.write("I love creating new games.\n")

I love programming.
I love creating new games.
  • Appending to a File


filename = 'programming.txt'
message.py
with open(filename, 'a') as file_object:
    file_object.write("I also love finding meaning in large datasets.\n")
    file_object.write("I love creating apps that can run in a browser.\n")

I love programming.
I love creating new games.
I also love finding meaning in large datasets.
I love creating apps that can run in a browser.

Exceptions


print("Give me two numbers, and I'll divide them.")
print("Enter 'q' to quit.")
while True:
    first_number = input("\nFirst number: ")
    if first_number == 'q':
        break
    second_number = input("Second number: ")
    try:
        answer = int(first_number) / int(second_number)
    except ZeroDivisionError:
        print("You can't divide by 0!")
    else:
        print(answer)

Give me two numbers, and I'll divide them.
Enter 'q' to quit.

First number: 5
Second number: 0
You can't divide by 0!

First number: 5
Second number: 2
2.5
First number: q
  • Handling the FileNotFoundError Exception


filename = 'alice.txt'
with open(filename) as f_obj:
    contents = f_obj.read() #Error

filename = 'alice.txt'
try:
    with open(filename) as f_obj:
        contents = f_obj.read()
except FileNotFoundError:
    msg = "Sorry, the file " + filename + " does not exist."
    print(msg)

Sorry, the file alice.txt does not exist.

filename = 'alice.txt'
try:
    with open(filename) as f_obj:
        contents = f_obj.read()
except FileNotFoundError:
    msg = "Sorry, the file " + filename + " does not exist."
    print(msg)

else:
# Count the approximate number of words in the file.
    words = contents.split()
    num_words = len(words)
    print("The file " + filename 
    + " has about " + str(num_words) + " words.")
  • Working with Multiple Files


def count_words(filename):
    """Count the approximate number of words in a file."""
    try:
        with open(filename) as f_obj:
            contents = f_obj.read()
    except FileNotFoundError:
        msg = "Sorry, the file " + filename + " does not exist."
        print(msg)
    else:
    # Count approximate number of words in the file.
    words = contents.split()
    num_words = len(words)
    print("The file " + filename + " has about " 
        + str(num_words) +" words.")

filename = 'alice.txt'
count_words(filename)

filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
for filename in filenames:
    count_words(filename)

10.4 Storing Data, Test

JSON


import json

numbers = [2, 3, 5, 7, 11, 13]
filename = 'numbers.json'
with open(filename, 'w') as f_obj:
    json.dump(numbers, f_obj)

import json

filename = 'numbers.json'
with open(filename) as f_obj:
    numbers = json.load(f_obj)
print(numbers)

[2, 3, 5, 7, 11, 13]
  • Saving and Reading User-Generated Data


import json

username = input("What is your name? ")
filename = 'username.json'
with open(filename, 'w') as f_obj:
    json.dump(username, f_obj)
    print("We'll remember you when you come back, " + username + "!")

import json
filename = 'username.json'
with open(filename) as f_obj:
    username = json.load(f_obj)
    print("Welcome back, " + username + "!")

import json

filename = 'username.json'
try:
    with open(filename) as f_obj:
    username = json.load(f_obj)
except FileNotFoundError:
    username = input("What is your name? ")
    with open(filename, 'w') as f_obj:
        json.dump(username, f_obj)
        print("We'll remember you when you come back, " + username + "!")
else:
    print("Welcome back, " + username + "!")

What is your name? Eric #First time
We'll remember you when you come back, Eric!

Welcome back, Eric!
  • Refactoring


import json

def get_stored_username():
"""Get stored username if available."""
    filename = 'username.json'
    try:
        with open(filename) as f_obj:
            username = json.load(f_obj)
    except FileNotFoundError:
        return None
    else:
        return username

def greet_user():
"""Greet the user by name."""
    username = get_stored_username()
    if username:
        print("Welcome back, " + username + "!")
    else:
        username = input("What is your name? ")
        filename = 'username.json'
        with open(filename, 'w') as f_obj:
            json.dump(username, f_obj)
            print("We'll remember you when you come back, " + username + "!")

greet_user()

def get_stored_username():
"""Get stored username if available."""
    filename = 'username.json'
    try:
        with open(filename) as f_obj:
            username = json.load(f_obj)
    except FileNotFoundError:
        return None
    else:
        return username

def get_new_username():
"""Prompt for a new username."""
    username = input("What is your name? ")
    filename = 'username.json'
    with open(filename, 'w') as f_obj:
        json.dump(username, f_obj)
    return username

def greet_user():
"""Greet the user by name."""
    username = get_stored_username()
    if username:
        print("Welcome back, " + username + "!")
    else:
        username = get_new_username()
        print("We'll remember you when you come back, " + username + "!")
greet_user()

Testing your code

  • name_function.py


def get_formatted_name(first, last):
    full_name = first + ' ' + last
    return full_name.title()
  • Unit Tests and Test Cases


import unittest
from name_function import get_formatted_name

class NamesTestCase(unittest.TestCase):
    def test_first_last_name(self): # should start with test_
        formatted_name = get_formatted_name('janis', 'joplin')
        self.assertEqual(formatted_name, 'Janis Joplin')

unittest.main()

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK


def get_formatted_name(first, middle, last):
    full_name = first + ' ' + middle + ' ' + last
    return full_name.title()

E
======================================================================
ERROR: test_first_last_name (__main__.NamesTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 6, in test_first_last_name
    formatted_name = get_formatted_name('janis', 'joplin')
TypeError: get_formatted_name() missing 1 required positional argument: 'last'

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

def get_formatted_name(first, last, middle=''):
    if middle:
        full_name = first + ' ' + middle + ' ' + last
    else:
        full_name = first + ' ' + last
    return full_name.title()

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):
    def test_first_last_name(self):
        formatted_name = get_formatted_name('janis', 'joplin')
        self.assertEqual(formatted_name, 'Janis Joplin')
    def test_first_last_middle_name(self):
        formatted_name = get_formatted_name('wolfgang', 'mozart', 'amadeus')
        self.assertEqual(formatted_name, 'Wolfgang Amadeus Mozart')

unittest.main()

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

A Variety of Asset Methods


assertEqual(a, b) # Verify that a == b
assertNotEqual(a, b) # Verify that a != b
assertTrue(x) # Verify that x is True
assertFalse(x) # Verify that x is False
assertIn(item, list) # Verify that item is in list
assertNotIn(item, list) # Verify that item is not in list

Testing a Class


class AnonymousSurvey():

    def __init__(self, question):
        self.question = question
        self.responses = []

    def show_question(self):
        print(self.question)

    def store_response(self, new_response):
        self.responses.append(new_response)

    def show_results(self):
        print("Survey results:")
        for response in self.responses:
            print('- ' + response)

from survey import AnonymousSurvey

question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)

my_survey.show_question()
print("Enter 'q' at any time to quit.\n")
while True:
    response = input("Language: ")
    if response == 'q':
        break
    my_survey.store_response(response)

print("\nThank you to everyone who 
        participated in the survey!")
my_survey.show_results()

Testing the AnonymousSurvey Class


import unittest
from survey import AnonymousSurvey

class TestAnonmyousSurvey(unittest.TestCase):

    def test_store_single_response(self):
        question = "What language did you first learn to speak?"
        my_survey = AnonymousSurvey(question)
        my_survey.store_response('English')
        self.assertIn('English', my_survey.responses)

unittest.main()

.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

import unittest
from survey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    def test_store_single_response(self):
--snip--

    def test_store_three_responses(self):
        question = "What language did you first learn to speak?"
        my_survey = AnonymousSurvey(question)
        responses = ['English', 'Spanish', 'Mandarin']
        for response in responses:
            my_survey.store_response(response)
        for response in responses:
            self.assertIn(response, my_survey.responses)

unittest.main()

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
  • setUp()


import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):

    def setUp(self):
        question = "What language did you first learn to speak?"
        self.my_survey = AnonymousSurvey(question)
        self.responses = ['English', 'Spanish', 'Mandarin']

    def test_store_single_response(self):
        self.my_survey.store_response(self.responses[0])
        self.assertIn(self.responses[0], self.my_survey.responses)

    def test_store_three_responses(self):
        for response in self.responses:
            self.my_survey.store_response(response)
        for response in self.responses:
            self.assertIn(response, self.my_survey.responses)

unittest.main()

Summary

  • File, Test
    • Reading: Python Crash Course, Chapter 10, 11