多伦多大学 - 学习编程:写出高质量的代码

学习编程:写出高质量的代码

Completed Palindrome: Approaching the Problem 

判断所给的一个字符串是否是回文

def is_palindrome(s):
    """ (str) -> bool

    Return True if and only if s is a palindrome.
    
    >>> is_palindrome('noon')
    True
    >>> is_palindrome('racecar')
    True
    >>> is_palindrome('dented')
    False
    """
    return reverse(s) == s

def reverse(s):
    """ (str) -> str

    Return a reversed version of s.
    
    >>> reverse('hello')
    'olleh'
    >>> reverse('a')
    'a'
    """

    rev = ''
    # For each character in s, add that char to the beginning of rev.
    for ch in s:
        rev = ch + rev

    return rev
def is_palindrome_v2(s):
    """ (str) -> bool

    Return True if and only if s is a palindrome.

    >>> is_palindrome_v2('noon')
    True
    >>> is_palindrome_v2('racecar')
    True
    >>> is_palindrome_v2('dented')
    False
    """
    # the number of chars in s
    n = len(s)
    
    # Compare the first half of s to the reverse of the second half.
    return s[: n//2 ] == reverse( s[ n - n//2 :] )


def reverse(s):
    """ (str) -> str

    Return a reversed version of s.

    >>> reverse('hello')
    'olleh'
    >>> reverse('a"0
    'a'
    """
    rev = ''

    #For each character in s, add that char to the beginning of rev.

    for ch in s:
        rev = ch + rev
    return rev
    

def is_palindrome_v3(s):
    """ (str) -> bool

    Return True if and only if s is a palindrome.

    >>> is_palindrome_v3('noon')
    True
    >>> is_palindrome_v3('racecar')
    True
    >>> is_palindrome_v3('dented')
    False
    """

    i = 0
    j = len(s)-1

    while i<j and s[i] == s[j]:
        i = i+1
        j = j-1

    return j <= i

The Restaurant Recommendations Problem

The Problem: Write a function that has three parameters:
- a restarurant file opened for reading
- the price range ( one of $,$$,$$$,$$$$ )
- a list of cuisines.
It returns a list of restaurants ( in that price range serving at least one of those cuisines ) and their ratings sorted from highest to lowest

问题: 编写一个传入三个参数的函数
- 一个餐馆列表文件
- 一个价格($,$$,$$$,$$$$)美元符号越多说明消费越贵
- 一个美食列表( 注意是 list 哦 )
函数返回一个餐馆列表,其中的每一家餐馆都满足消费价格,并且至少提供美食列表中的一种食物。并且按照受欢迎程度降序排列。

"""
A restaurant recommendation system.

Here are some example dictionaries.
These correspond to the information in restaurants_small.txt.

Restaurant name to rating:
# dict of {str: int}
{'Georgie Porgie': 87,
 'Queen St. Cafe': 82,
 'Dumplings R Us': 71,
 'Mexican Grill': 85,
 'Deep Fried Everything': 52}

Price to list of restaurant names:
# dict of {str, list of str}
{'$': ['Queen St. Cafe', 'Dumplings R Us', 'Deep Fried Everything'],
 '$$': ['Mexican Grill'],
 '$$$': ['Georgie Porgie'],
 '$$$$': []}

Cuisine to list of restaurant names:
# dict of {str, list of str}
{'Canadian': ['Georgie Porgie'],
 'Pub Food': ['Georgie Porgie', 'Deep Fried Everything'],
 'Malaysian': ['Queen St. Cafe'],
 'Thai': ['Queen St. Cafe'],
 'Chinese': ['Dumplings R Us'],
 'Mexican': ['Mexican Grill']}

With this data, for a price of '$' and cuisines of ['Chinese', 'Thai'], we
would produce this list:

    [[82, 'Queen St. Cafe'], [71, 'Dumplings R Us']]
"""

# The file containing the restaurant data.
FILENAME = 'c:/restaurants.txt'


def recommend(file, price, cuisines_list):
    """(file open for reading, str, list of str) -> list of [int, str] list

    Find restaurants in file that are priced according to price and that are
    tagged with any of the items in cuisines_list.  Return a list of lists of
    the form [rating%, restaurant name], sorted by rating%.
    """
    # Read the file and build the data structures.
    name_to_rating , price_to_names , cuisine_to_names = read_restaurants(FILENAME);

    # Look for price or cuisines first
    # Price: look up the list of restaurant names for the requested price
    names_maching = price_to_names[price]

    # Now we have a list of restaurants in the right price range.
    # Need a new list of restaurants that serve one of the cuisines.
    names_final = filter_by_cuisine( names_maching , cuisine_to_names , cuisines_list );

    # Now we have a list of restaurants that are the right price and serve the requested cuisine.
    # Need to look at ratings and sort this list.
    result =  build_rating_list( name_to_rating , names_final )

    # We're done ! Return that sorted list.
    print( result )
    
def read_restaurants(file):
    """ (file) -> ( dict , dict , dict )

    Return a tuple of three dictionaries based on information in the file:
    - a dict of { restaurant name: rating% }
    - a dict of { price: list of restaurant names }
    - a dict of { cuisine: list of restaurant names }
    """

    name_to_rating = {}
    price_to_names = { '$': [] , '$$': [] , '$$$': [] , '$$$$': [] }
    cuisine_to_names = {}

    fobj = open(file)
    lines = fobj.readlines()
    
    for i in range(0,len(lines),5):
        restaurant_name = lines[i].replace('\n','')
        rating = int( lines[i+1].replace('%','').replace('\n','') )
        price = lines[i+2].replace('\n','')
        cuisines = lines[i+3].replace('\n','').split(',')

        # build name_to_rating dic
        name_to_rating[restaurant_name] = rating

        # build price_to_names dic
        price_to_names[price].append(restaurant_name);

        # build cuisine_to_names dic
        for c in cuisines:
            if not(c in cuisine_to_names):
                cuisine_to_names[c] = []
            cuisine_to_names[c].append(restaurant_name)
           
    return ( name_to_rating , price_to_names , cuisine_to_names )

def filter_by_cuisine( names_matching , cuisine_to_names , cuisines_list ):
    """ (list of str, dict of {str: list of str}, list of str) -> list of str

    >>> names = ['Queen St. Cafe', 'Dumplings R Us', 'Deep Fried Everything']
    >>> cuis = 'Canadian': ['Georgie Porgie'],
     'Pub Food': ['Georgie Porgie', 'Deep Fried Everything'],
     'Malaysian': ['Queen St. Cafe'],
     'Thai': ['Queen St. Cafe'],
     'Chinese': ['Dumplings R Us'],
     'Mexican': ['Mexican Grill']}
    >>> cuisines = ['Chinese', 'Thai']
    >>> filter_by_cuisine(names, cuis, cuisines)
    ['Queen St. Cafe', 'Dumplings R Us']
    """
    names_final = [];
    
    for c in cuisines_list:
        for n in names_matching:
            if n in cuisine_to_names[c] and not( n in names_final ):
                names_final.append(n)

    return names_final

def build_rating_list(name_to_rating, names_final):
    """ (dict of {str: int}, list of str) -> list of list of [int, str]

    Return a list of [rating%, restaurant name], sorted by rating%

    >>> name_to_rating = {'Georgie Porgie': 87,
     'Queen St. Cafe': 82,
     'Dumplings R Us': 71,
     'Mexican Grill': 85,
     'Deep Fried Everything': 52}
    >>> names = ['Queen St. Cafe', 'Dumplings R Us']
    [[82, 'Queen St. Cafe'], [71, 'Dumplings R Us']]
    """

    result = []
    for n in names_final:
        result.append([ name_to_rating[n] , n ])
        
    result.sort()
    result.reverse()
    return result

Testing Automatically using doctest

doctest用于检查一个模块的文档字符串的描述是否正确

def collect_vowels(s):
    ''' (str) -> str

    Return the vowels (a,e,i,o and u) from s.
    >>> collect_vowels('Happy Anniversary!')
    'aAiea'
    >>> collect_vowels('xyz')
    ''
    '''

    vowels = ''

    for char in s:
        if char in 'aeiouAEIOU':
            vowels = vowels + char
    return vowels

def count_vowels(s):
    ''' (str) -> int

    Return the number of vowels in s.
    >>> count_vowels('Happy Anniversary!')
    5
    >>> count_vowels('xyz')
    0
    '''

    num_vowels = 0
    for char in s:
        if char in 'aeiouAEIOU':
            num_vowels = num_vowels + 1
    return num_vowels

import doctest
doctest.testmod()

Writing a "__main__" program

当编写一个模块,其中有一段代码只想让直接调用该模块时执行。而当其他模块import这个模块的时候不执行,可以这样做:

palindrome_v1.py

def is_palindrome_v1(s):
    """ (str) -> bool
 
    Return True if and only if s is a palindrome.
     
    >>> is_palindrome('noon')
    True
    >>> is_palindrome('racecar')
    True
    >>> is_palindrome('dented')
    False
    """
    return reverse(s) == s
 
def reverse(s):
    """ (str) -> str
 
    Return a reversed version of s.
     
    >>> reverse('hello')
    'olleh'
    >>> reverse('a')
    'a'
    """
 
    rev = ''
    # For each character in s, add that char to the beginning of rev.
    for ch in s:
        rev = ch + rev
 
    return rev

print ( "This is palindrome v1, the module name is ", __name__ )

if __name__ == '__main__': # 判断是否是被其他模块import
    word = input("Enter a world: ")
    if is_palindrome_v1(word):
        print(word, 'is a palindrome.')
    else:
        print(word, 'is not a palindrome.')

palindrome_v2

def is_palindrome_v2(s):
    """ (str) -> bool
 
    Return True if and only if s is a palindrome.
 
    >>> is_palindrome_v2('noon')
    True
    >>> is_palindrome_v2('racecar')
    True
    >>> is_palindrome_v2('dented')
    False
    """
    # the number of chars in s
    n = len(s)
     
    # Compare the first half of s to the reverse of the second half.
    return s[: n//2 ] == reverse( s[ n - n//2 :] )

import palindrome_v1

Creating your own types

class WordplayStr(str):
    """A string that can report whether it has interesting properties"""

    def same_start_and_end(self):
        """ (WordplayStr) -> bool

        Precondition: len(self) > 0

        Return whether self starts and ends with the same letter.

        >>> s = WordplayStr('abcba')
        >>> s.same_start_and_end()
        True
        >>> s = WordplayStr('cace')
        >>> s.same_start_and_end()
        False
        """

        return self[0] == self[-1]

if __name__ == '__main__':
    import doctest
    doctest.testmod()

Testing Automatically Using unittest

divisors.py

def get_divisors(num, possible_divisors):
    ''' (int, list of int) -> list of int

    Return a list of the values from possible_divisors
    that are divisors of num.

    >>> get_divisors(8, [1,2,3])
    [1, 2]
    >>> get_divisors(4, [-2,0,2])
    [-2, 2]
    '''

    divisors = []
    for item in possible_divisors:
        if item !=0 and num % item == 0:
            divisors.append(item)
    return divisors

if __name__ == '__main__':
    import doctest
    doctest.testmod()

unittest_example.py

import unittest
import divisors

class TestDivisors(unittest.TestCase):
    """ Example unittest test mehtods for get_divisors."""

    def test_divisors_example_1(self):
        """ Test get_divisros with 8 and [1,2,3]."""
        actual = divisors.get_divisors(8, [1,2,3])
        expected = [1, 2]
        self.assertEqual( actual, expected)

    def test_divisors_example_2(self):
        """ Test get_divisros with 4 and [-2,0,2]."""
        actual = divisors.get_divisors(4, [-2,0,2])
        expected = [-2, 2]
        self.assertEqual( actual, expected)

if __name__ == '__main__':
    unittest.main(exit=False)

Another Unittest Example

duplicates.py

def remove_shared(L1,L2):
    """ (list list)

    Remove items from L1 that are in both L1 and L2.
    >>> list_1 = [1,2,3,4,5,6]
    >>> list_2 = [2,4,5,7]
    >>> remove_shared(list_1,list_2)
    >>> list_1
    [1, 3, 6]
    >>> list_2
    [2, 4, 5, 7]
    """

    for v in L2:
        if v in L1:
            L1.remove(v)
            
if __name__ == '__main__':
    import doctest
    doctest.testmod()

test_duplicates.py

import unittest
import duplicates

class TestRemoveShared(unittest.TestCase):
    """Tests for function duplicates.remove_shared."""

    def test_general_case(self):
        """
        Test remove_shared where there are items that
        appear in both lists, and items that appear in
        only one or the other list.
        """

        list_1 = [1,2,3,4,5,6]
        list_2 = [2,4,5,7]
        list_1_expected = [1,3,6]
        list_2_expected = [2,4,5,7]

        duplicates.remove_shared(list_1,list_2)
        self.assertEqual(list_1,list_1_expected)
        self.assertEqual(list_2,list_2_expected)

if __name__ == '__main__':
    unittest.main(exit=False)
posted @ 2015-01-25 15:33  saintyk  阅读(574)  评论(0编辑  收藏  举报