1. 程式人生 > >《Python核心程式設計》第13章 面向物件程式設計 練習

《Python核心程式設計》第13章 面向物件程式設計 練習

13-3.對類進行定製。

寫一個類,用來將浮點型值轉換為金額。

class MoneyFmt(object):
    def __init__(self, value=0.0):
        self.value = float(value)

    def update(self, value=None):
        if value != None:
            self.value = float(value)

    def __repr__(self):
        return `self.value`

    def __str__(self):
        pre = '$' if self.value >= 0 else '-$'
        return pre + str(round(abs(self.value), 2))

    def __nonzero__(self):
        return self.value > 0.5
13-4.使用者註冊。

建立一個使用者資料庫類,來管理一個系統,該系統要求使用者在登入後才能訪問某些資源。這個資料庫類對使用者進行管理,並在例項化操作時載入之前儲存的使用者資訊,提供訪問函式來新增或更新資料庫的資訊。在資料修改後,資料庫會在垃圾回收時將新資訊儲存到磁碟。

import shelve
import os
import time

class UserData(object):
    def __init__(self, dbfile):
        self._db = {}
        if os.path.exists(dbfile):
            self._db = shelve.open(dbfile, 'r')
        self._dbfile = dbfile

    def __del__(self):
        data = shelve.open(self._dbfile, 'c')
        data.update(self._db)
        data.close()

    def update(self, name, passwd):
        self._db[name] = [passwd, time.time()]

    def delete(self, name):
        self._db.pop(name)

    def login(self, name, passwd):
        if self._db.get(name, None)[0] == passwd:
            self._db[name][1] = time.time()
            return True
        return False

    def listall(self):
        for name in self._db:
            print name, self._db[name][0], time.ctime(self._db[name][1])
13-5.幾何。

建立一個由有序數值對(x,y)組成的Point類,代表某個點的X和Y座標。

class Point(object):
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __str__(self):
        return '(%d, %d)' % (self.x, self.y)

    __repr__ = __str__
13-6.幾何。

建立一個直線類,除主要屬性:一對座標值外,它還具有長度和斜線屬性。你需要覆蓋__repr__()方法,使得代表那條直線的字串表示形式是由一對元組構成的元組。

from math import sqrt

class Line(object):
    def __init__(self, x1=0, y1=0, x2=0, y2=0):
        self.p1 = Point(x1, y1)
        self.p2 = Point(x2, y2)

    def __str__(self):
        return '(%s, %s)' % (str(self.p1), str(self.p2))

    __repr__ = __str__

    def slope(self):
        try:
            k = float(self.p2.y - self.p1.y) / (self.p2.x - self.p1.x)
        except ZeroDivisionError:
            k = None
        return k

    def length(self):
        return sqrt((self.p2.y - self.p1.y)**2 + (self.p2.x - self.p1.x)**2)
13-7.資料類。

提供一個time模組的介面,允許使用者按照自己給定的時間格式來檢視日期。你的類應該維護一個日期值,並用給定的時間建立一個例項,如果沒有給出時間值,程式執行時會預設採用當前的系統時間。

import time

class TimeFmt(object):

    def __init__(self, time=time.time()):
        self.__time = time

    def update(self, time=time.time()):
        self.__time = time

    def display(self, fmt=None):
        fmtdb = {}
        fmtdb['MDY'] = '%m/%d/%y'
        fmtdb['MDYY'] = '%m/%d/%Y'
        fmtdb['DMY'] = '%d/%m/%y'
        fmtdb['DMYY'] = '%d/%m/%Y'
        fmtdb['MODYY'] = '%m %d, %Y'
        if fmt in fmtdb:
            t = time.localtime(self.__time)
            print time.strftime(fmtdb[fmt], t)
        else:
            print time.ctime(self.__time)
13-8.堆疊類。

實現一個堆疊類,類中應該有push()和pop()方法,還有一個isempty()方法,如果堆疊是空的,返回布林值1,否則返回0。

class Stack(object):

    def __init__(self):
        self.__ls = []

    def push(self, obj):
        self.__ls.append(obj)

    def pop(self):
        if not self.isempty():
            return self.__ls.pop()

    def isempty(self):
        return len(self.__ls) == 0

    def peek(self):
        return self.__ls[len(self.__ls)-1]
13-9.佇列類。

實現一個佇列類,這個類必須支援下面幾種方法:enqueue()在佇列的尾部加入一個新的元素,dequeue()在佇列的頭部取出一個元素,返回它並且把它從列表中刪除。

class Queue(object):

    def __init__(self):
        self.__ls = []

    def __str__(self):
        return str(self.__ls)

    def enqueue(self, obj):
        self.__ls.append(obj)

    def dequeue(self):
        if not self.isempty():
            return self.__ls.pop(0)

    def isempty(self):
        return len(self.__ls) == 0
13-11.電子商務。

你需要為一家B2C零售商編寫一個基礎的電子商務引擎。你需要寫一個針對顧客的類User,一個對應存貨清單的類Item,還有一個對應購物車的類叫Cart。貨物放到購物車裡,顧客可以有多個購物車。同時購物車裡可以有多個貨物,包括多個同樣的貨物。

class Item(object):

    def __init__(self, name, price):
        self.name = name
        self.price = price


class Cart(object):

    def __init__(self):
        self.ls = {}

    def append(self, item, count):
        if item not in self.ls:
            self.ls[item] = count
        else:
            self.ls[item] += count

    def delete(self, item, count):
        if (item in self.ls) and (self.ls[item] >= count):
            self.ls[item] -= count
            if self.ls[item] == 0:
                self.ls.pop(item)


class User(object):

    def __init__(self):
        self.ls = []

    def append(self, cart):
        self.ls.append(cart)

    def delete(self, cart):
        self.ls.remove(cart)   
13-12.聊天室。

你需要三個類:一個Message類,它包含一個訊息字串以及諸如廣播、單方收件人等其他資訊。一個User類,包含了進入你聊天室的某個人的所有資訊。一個Room類,它體現了一個更加複雜的聊天系統,使用者可以在聊天時建立單獨的房間,並邀請其他人加入。

class Message(object):

    def __init__(self, info='', isbroad=False, to='', froms=''):
        self.info = info
        self.isbroad = isbroad
        self.to = to
        self.froms = froms

    def __str__(self):
        if self.isbroad:
            msg = '%s say to everone: %s' % (self.froms, self.info)
        else:
            msg = '%s say to %s: %s' % (self.froms, self.to, self.info)
        return msg


class User(object):

    def __init__(self, name='', sex=True, age=18):
        self.name = name
        self.sex = sex
        self.age = age

    def __str__(self):
        return '%s %s %s' % (self.name, self.sex, self.age)

    def say(self, room, info, to=''):
        if to == '':
            msg = Message(info, True, '', self.name)
        else:
            msg = Message(info, False, to, self.name)
        room.receive(msg)

    def hear(self, msg):
        print msg

    def createroom(self, name):
        return Room(name)


class Room(object):

    def __init__(self, name):
        self.name = name
        self.userlist = []

    def add(self, user):
        self.userlist.append(user)

    def receive(self, msg):
        if msg.isbroad:
            print msg
        else:
            for user in self.userlist:
                if user.name == msg.to:
                    user.hear(msg)

 

if __name__ == '__main__':
    user1 = User('Tom', True, 16)
    user2 = User('Lily', False, 15)
    user3 = User('Lucy', False)

    room = user1.createroom('chatting room')
    room.add(user1)
    room.add(user2)
    room.add(user3)
   
    user1.say(room, 'Hi, Lily', 'Lily')
    user2.say(room, 'Hello, Tom', 'Tom')
    user3.say(room, 'Hey, you two')

13-14.DOS。

為DOS機器編寫一個Unix操作介面的shell。你向用戶提供一個命令列,使得使用者可以在那裡輸入unix命令,你可以對這些命令進行解釋,並把返回相應的輸出。

import os

class Shell(object):

    def __init__(self):
        self.cmds = {'ls': 'dir', 'cat': 'type', 'rm': 'del'}

    def translate(self, cmd):
        words = cmd.split()
        if words[0] in self.cmds:
            words[0] = self.cmds[words[0]]
        return ' '.join(words)

    def start(self):
        while True:
            cmd = raw_input('$')
            cmd = self.translate(cmd)
            if cmd == 'exit':
                break
            else:
                f = os.popen(cmd)
                for data in f:
                    print data,
                print
                f.close()

if __name__ == '__main__':
    sh = Shell()
    sh.start()
13-16.授權和函式程式設計。
(a)請為示例中的CanOpen類編寫一個writelines()方法,這個新函式可以一次讀入多行文字,然後將文字轉化為大寫的形式。
(b)在writelines()方法中新增一個引數,用這個引數來指明是否需要為每行文字加上一個換行符。此引數的預設值是False,表示不加換行符。
from os import linesep

class CanOpen(object):

    def __init__(self, fn, mode='r', buf=-1):
        self.file = open(fn, mode, buf)

    def __str__(self):
        return str(self.file)

    def __repr__(self):
        return `self.file`

    def write(self, line):
        self.file.write(line.upper())

    def writelines(self, lines, newline=False):
        for line in lines:
            if newline:
                line += linesep
            self.file.write(line.upper())

    def __getattr__(self, attr):
        return getattr(self.file, attr)
13-20.類的定製。改進指令碼time60.py
(a)允許“空”例項化:如果小時和分鐘的值沒有給出,預設為0小時0分鐘。
(b)用0佔位組成兩位數的形式,因為當前的時間格式不符合要求。
(c)除了用hours(hr)和minutes(min)進行初始化外,還支援以下時間輸入格式:
一個由小時和分鐘組成的元組,如(10,30)
一個由小時和分鐘組成的字典,如{'hr':10, 'min':30}
一個代表小時和分鐘的字串,如"10:30"
(e)實現__repr__()。
(f)新增60進位制的運算功能。
class Time60(object):
    'Time60 - track hours and minutes'

    def __init__(self, hr=0, min=0):
        if isinstance(hr, basestring):
            t = hr.split(':')
            self.hr = int(t[0])
            self.min = int(t[1])
        else:
            self.hr = hr
            self.min = min

    def __str__(self):
        return '%02d:%02d' % (self.hr, self.min)

    def __repr__(self):
        return "%s('%s')" % (self.__class__.__name__, str(self))

    def add60(self, other):
        hr = self.hr + other.hr
        min = self.min + other.min
        carry = min // 60
        min %= 60
        hr += carry
        return (hr, min)

    def __add__(self, other):
        return self.__class__(*self.add60(other))

    def __iadd__(self, other):
        (self.hr, self.min) = self.add60(other)
        return self

if __name__ == '__main__':
    print Time60()
    print Time60(12,5)
    print Time60(*(10, 30))
    print Time60(**{'hr': 10, 'min': 30})
    print Time60('10:30')
    print `Time60('10:10')`
    print Time60(10, 30) + Time60(8, 45)