多伦多大学 - 学习编程:写出高质量的代码
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)

浙公网安备 33010602011771号