7–1. 字典方法。
哪个字典方法可以用来把两个字典合并到一起?
#update方法
7–2. 字典的键。我们知道字典的值可以是任意的Python 对象,那字典的键又如何呢?请试着将除数字和字符串以外的其他不同类型的对象作为字典的键,看一看,哪些类型可以,哪些不行?对那些不能作字典的键的对象类型,你认为是什么原因呢?
#字典的健必须是可哈希的对象,包括所有不可变类型,和实现了__hash__()特殊方法的类。对于列表之类的可变对象,不能作为字典的键。因为解释器调用哈希函数,来根据键值计算得到数据的存储位置,如果键是可变的,那么位置的计算就会不可靠。
7–3. 字典和列表的方法。
dc = {'hell': 'x', 'hello': 'tree', 'test': 'failed'}
for x in sorted(dc):
print x,
for x in sorted(dc):
print 'key=', x, 'value=', dc[x]
items = dc.items()
for value in sorted(dc.values()):
for k, v in items:
if value == v:
print 'key=', k, 'value=', v
items.remove((k, v))
break
7-4. 建立字典。
给定两个长度相同的列表,比如说,列表[1, 2, 3,...]和['abc', 'def','ghi',...],用这两个列表里的所有数据组成一个字典,像这样:{1:'abc', 2: 'def', 3: 'ghi',...}
def build_dict(list1, list2):
assert len(list1) == len(list2)
return dict(zip(list1, list2))
if __name__ == '__main__':
list1 = [1, 2, 3, 4]
list2 = ['abc', 'def', 'ghi', 'jkl']
print build_dict(list1, list2)
7–5. userpw2.py.
下面的问题和例题7.1 中管理名字-密码的键值对数据的程序有关。
(a)修改那个脚本,使它能记录用户上次的登录日期和时间(用time 模块),并与用户密码一起保存起来。程序的界面有要求用户输入用户名和密码的提示。无论户名是否成功登录,都应有提示,在户名成功登录后,应更新相应用户的上次登录时间戳。如果本次登录与上次登录在时间上相差不超过4 个小时,则通知该用户: “You already logged in at:
(b) 添加一个“管理”菜单,其中有以下两项:(1)删除一个用户 (2)显示系统中所有用户的名字和他们的密码的清单。
(c) 口令目前没有加密。请添加一段对口令加密的代码(请参考crypt, rotor, 或其它加密模块)
(d) 为程序添加图形界面,例如,用Tkinter 写。
(e) 要求用户名不区分大小写。
(f) 加强对用户名的限制,不允许符号和空白符。
(g)合并“新用户”和“老用户”两个选项。如果一个新用户试图用一个不存在的用户名登录,
询问该用户是否是新用户,如果回答是肯定的,就创建该帐户。否则,按照老用户的方式登录。
#!/usr/bin/env python
import time
import md5
import base64
db = {}
log = {}
def newuser():
prompt = 'login desired: '
while True:
name = raw_input(prompt).lower()
if not checkname(name):
prompt = 'invalid name, try again: '
continue
if db.has_key(name):
prompt = 'name taken, try another: '
continue
else:
break
pwd = raw_input('password: ')
db[name] = encodepwd(pwd)
def olduser():
name = raw_input('login: ').lower()
if name not in db:
choice = raw_input('register a new user? y/n')
if choice == 'y':
newuser()
return
pwd = raw_input('password: ')
passwd = db.get(name)
if passwd == encodepwd(pwd):
if time.time() - log.get(name, 0) < 4 * 3600:
print 'You already logged in at: %s' % time.ctime(log.get(name))
else:
print 'welcome back', name
log[name] = time.time()
else:
print 'login incorrect'
def deluser():
name = raw_input('which user: ')
if name in db:
del db[name]
if name in log:
del log[name]
print 'delete user succeed'
def listusers():
for key in db:
print key, db[key]
def encodepwd(passwd):
pwd = md5.new()
pwd.update(passwd)
return base64.encodestring(pwd.digest())
def checkname(name):
return name.isalnum()
def showmenu():
prompt = """
(U)User Login
(D)elte User
(L)ist Users
(Q)uit
Enter choice:"""
done = False
while not done:
chosen = False
while not chosen:
try:
choice = raw_input(prompt).strip()[0].lower()
except (EOFError, KeyboardInterrupt):
choice = 'q'
print '\nYour picked: [%s]' % choice
if choice not in 'udlq':
print 'invalid option, try again'
else:
chosen = True
if choice == 'q': done = True
if choice == 'd': deluser()
if choice == 'l': listusers()
if choice == 'u': olduser()
if __name__ == '__main__':
showmenu()
7-6. 列表和字典。
创建一个简单的股票证券投资数据系统。其中应至少包含四项数据:股市行情显示器符号,所持有的股票,购买价格及当前价位 - 你可以随意添加其他数据项,比如收益率,
52 周最高指数、最低指数,等等。用户每次输入各列的数据构成一个输出行。每行数据构成一个列表。还有一个总列表,包括了所有行的数据。数据输入完毕后,提示用户选择一列数据项进行排序。把该数据项抽取出来作为字典的键,字典的值就是该键对应行的值的列表。提醒读者:被选择用来排序的数据项必须是非重复的键,否则就会丢失数据,因为字典不允许一个键有多个值。你还可以选择其他计算输出,比如,盈亏比率,目前证券资产价值等。
info = []
while True:
market = raw_input('market: ')
if market == '-1': break
stock = raw_input('stock: ')
price = float(raw_input('price: '))
current = float(raw_input('current: '))
info += [[market, stock, price, current]]
order = {'market': 0, 'stock': 1, 'price': 2, 'current': 3}
col = order.get(raw_input('item: '), 0)
key = zip(*info)[col]
data = dict(zip(key, info))
key = list(key)
key.sort()
for k in key:
print data[k]
7-7. 颠倒字典中的键和值。
用一个字典做输入,输出另一个字典,用前者的键做值,前者的值做键。
d1 = {1: 'apple', 2: 'microsoft', 3: 'yahoo', 4: 'google'}
data = zip(*d1.items())
data.reverse()
d2 = dict(zip(*data))
print d2
7-8. 人力资源。
创建一个简单的雇员姓名和编号的程序。让用户输入一组雇员姓名和编号。你的程序可以提供按照姓名排序输出的功能,雇员姓名显示在前面,后面是对应的雇员编号。附加
题:添加一项功能,按照雇员编号的顺序输出数据。
db1 = {}
db2 = {}
while True:
name = raw_input('name: ')
if name == '-1': break
pid = raw_input('id: ')
db1[name] = pid
db2[pid] = name
for key in sorted(zip(*db1.items())[0]):
print key, db1[key]
for key in sorted(zip(*db2.items())[0]):
print key, db2[key]
def tr(srcstr, dststr, string, casemap=True):
assert len(srcstr) >= len(dststr)
table = dict(zip(srcstr, dststr))
if len(srcstr) > len(dststr):
temp = {}.fromkeys(srcstr[len(dststr):])
table.update(temp)
ls = []
for ch in string:
if not casemap:
if ch.lower() in table:
ls.append(table[ch.lower()])
elif ch.upper() in table:
ls.append(table[ch.upper()])
else:
ls.append(ch)
continue
if ch in table:
ls.append(table[ch])
else:
ls.append(ch)
ls = [ch for ch in ls if ch]
return ''.join(ls)
print tr('abc', 'mno', 'abcdef')
print tr('aBcdef', 'mno', 'abcdefghi', False)
7–10. 加密。
def rot13(srcstr):
ls1 = [chr((num + 13) % 26 + ord('a')) for num in range(26)]
ls2 = [chr(num + ord('a')) for num in range(26)]
table = dict(zip(ls2, ls1))
ls1 = "".join(ls1).upper()
ls2 = "".join(ls2).upper()
table.update(zip(ls2, ls1))
ls = []
for ch in srcstr:
if ch in table:
ls.append(table[ch])
else:
ls.append(ch)
return "".join(ls)
7–13. 随机数。
修改练习5-17 的代码:使用random 模块中的randint()或randrange()方法生成一个随机数集合:从0 到9(包括9)中随机选择,生成1 到10 个随机数。这些数字组成集合
A(A 可以是可变集合,也可以不是)。同理,按此方法生成集合B。每次新生成集合A 和B 后,显示结果 A | B 和 A & B
from random import randint
ls1 = [randint(0, 9) for i in range(randint(1, 10))]
ls2 = [randint(0, 9) for i in range(randint(1, 10))]
a = frozenset(ls1)
b = frozenset(ls2)
print a & b
print a | b
7–15. 编写计算器。
这个练习取材于http://math.hws.edu/ 在线免费Java 教材中的练习12.2。编写一个程序允许用户选择两个集合:A 和B, 及运算操作符。例如,in, not in, &, |, ^, <,<=, >, >=, ==, !=, 等. (你自己定义集合的输入语法,它们并不一定要像Java 示例中那样用方括号括住。)解析输入的字符串,按照用户选择的运算进行操作。你写的程序代码应该比Java 版本的
该程序更简洁。
def compute(a, b, op):
foo = {}
foo['in'] = lambda x, y: x in y
foo['not in'] = lambda x, y: x not in y
foo['&'] = lambda x, y: x & y
foo['|'] = lambda x, y: x | y
foo['^'] = lambda x, y: x ^ y
foo['<'] = lambda x, y: x < y
foo['<='] = lambda x, y: x <= y
foo['>'] = lambda x, y: x > y
foo['>='] = lambda x, y: x >= y
foo['=='] = lambda x, y: x == y
foo['!='] = lambda x, y: x != y
foo['-'] = lambda x, y: x - y
if op not in foo:
return None
return foo[op](a, b)
def main():
ls1 = eval(raw_input('A: '))
ls2 = eval(raw_input('B: '))
a = set(ls1)
b = set(ls2)
op = raw_input('operator: ')
print compute(a, b, op)
if __name__ == '__main__':
main()