【python核心编程笔记+习题】-CH13-面向对象编程-上

本章主题
引言
面向对象编程类
实例
绑定与方法调用子类,派生和继承内建函数
定制类
私有性
授权与包装
新式类的高级特性相关模块

 

 

调用一个方法:定义类(类中定义方法);创建实例;用实例调用方法

python中的类 可仅作名称空间----像 Pascal 中的记录集(records)和 C 语言中的结构体(structures)一样的特性。

在 Python 中,方法定义在类定义中,但只能被实例所调用。----结合兔子工厂图理解

class MyDataWithMethod(object): # 定义类

def printFoo(self): # 定义方法
print 'You invoked printFoo()!'

>>> myObj = MyDataWithMethod() # 创建实例

>>> myObj.printFoo() # 现在调用方法
You invoked printFoo()!

 

一个特殊的方法__init__()--------类似构造器,可以 认为一个构造器仅是一个特殊的方法,它在创建一个新的对象时被调用。

这就是实例化调用,它会自动调用__init__()。self 把实例对象自动传入__init__()。你可以 在脑子里把方法中的 self 用实例名替换掉。

创建子类

EmplAddrBookEntry。Python 中,当一个类被派生出来,子类继 承了基类的属性,所以,在上面的类中,我们不仅定义了__init__(),updatEmail()方法,而且 EmplAddrBookEntry 还从 AddrBookEntry 中继承了 updatePhone()方法。

每个子类最好定义它自己的构造器,如果子 类重写基类的构造器,基类的构造器就不会被自动调用了--这样,基类的构造器就必须显式写出 才会被执行,像我们上面那样,⚠️用 AddrBookEntry.__init__()设置名字和电话号码。

命名类、属性和方法

⚠️类-----大写字母开头class ClassName(object) ,如 EmplAddrBookEntry、AddrBookEntry ; 

数据值---名字命名,如 像“name”,“phone; 

方法----谓词(动词+对象)命名,如 “updatePhone”或“update_phone”,即常说的“混合记法(mixedCase)”或“骆驼记法(camelCase)”;

函数-----def functionName(args): 

创建函数--在文件中(方法定义在类中)

创建类

类体=所有声明语句+类成员定义+数据属性和函数组成。

请注意 Python 并不支持纯虚函数(像 C++)或 者抽象方法(如在 JAVA 中),这些都强制程序员在子类中定义方法。作为替代方法,你可以简单地 在基类方法中引发 NotImplementedError 异常,这样可以获得类似的效果。

什么是属性呢?

属性就是属于另一个对象的数据或者函数元素,可以通过我们熟悉的句点属性 标识法来访问。一些 Python 类型比如复数有数据属性(实部和虚部),而另外一些,像列表和字典, 拥有方法(函数属性)。

如何知道一个类有哪些属性? 通过函数或属性

--使用dir()内建函数dir(MyClass)  返回的是对象的属性的名字列表;

--访问类的字典属性__dict__,这是所有类都具备的特殊属性之一。MyClass.__dict__,返回的是字典,是属性名和属性值的键值对

python支持模块间对类继承,通过特殊属性__module__定位类的位置

__init__() "构造器"方法

一旦对象创建了,Python 检查是否实现了 __init__()方法。默认情况下,如果没有定义(或覆盖)特殊方法__init__(),对实例不会施加任 何特别的操作.任何所需的特定操作,都需要程序员实现__init__(),覆盖它的默认行为。

⚠️构造器是最早可以设置实例属性的地方,因为__init__()是实例创建后第一个被调用的方法。__init__()就不应当返回任何对象(应当为 None)

__new__() “构造器”方法

需要一种途径来实例化不可变对象,比如,派生字符 串,数字,等等。在这种情况下,解释器则调用类的__new__()方法,一个静态方法,并且传入的参数是在类实例 化操作时生成的。__new__()会调用父类的__new__()来创建对象(向上代理)。

__del__() "解构器"方法

这个函数要直到该实例对象所有的引用都被清除掉后才会执行。Python 中的解构器是在实例释放前提供特殊处理功能的方法,它们通常没有被实现,因为实例很少 被显式释放。

Python 类的优秀特性:能够在“运行时”创建实例属性;

⚠️使用类属性来修改自身(不是实例属性)

绑定和方法调用

方法仅仅是类内部定义的函数。(这意味着方法是类属性而不 是实例属性)。方法只有在其所属的类拥有实例时,才能被调用。当存在一个实例时,方法才被认为是 绑定到那个实例了。没有实例时方法就是未绑定的。

self 是什么?

self 变量用于在类实例方法中引用方法所绑定的实例。因为方法的实例在任何方法调用中总是 作为第一个参数传递的,self 被选中用来代表实例。你必须在方法声明中放上 self(你可能已经注 意到了这点),但可以在方法中不使用实例(self)。如果你的方法中没有用到 self , 那么请考虑创建 一个常规函数,除非你有特别的原因。毕竟,你的方法代码没有使用实例,没有与类关联其功能, 这使得它看起来更像一个常规函数。在其它面向对象语言中,self 可能被称为 this。

创建静态方法和类方法----staticmethod()和 classmethod()内建函数

通过类或者实例对象去调用 静态方法和 类方法

创建子类                                                                 如果没有任何继承,可以使用 object 作为父类的名字

继承特性

C 没有声明__init__()方法,然而在类 C 的实例 c 被创建时,还是会有输出信息。原因在于 C 继 承了 P 的__init__()。__bases__元组列出了其父类 P。需要⚠️的是文档字符串对类,函数/方法, 还有模块来说都是唯一的,所以特殊属性__doc__不会从基类中继承过来。

继承覆盖(Overriding)---如何调用那个被我覆盖的基类方法--在子类的重写方法里显式地调用基类方法

在这个(未绑定)方法调用中我们显式地传递了 self. 一个更好的办法是使用 super() 内建方法:

⚠️在 JAVA 中,不管程序员如何处理,子类构造器都会去调 用基类的的构造器。

多重继承

类、实例和其他对象的内建函数

         issubclass() 布尔函数判断一个类是另一个类的子类或子孙类。语法:  issubclass(sub, sup)

         isinstance() 布尔函数在判定一个对象是否是另一个给定类的实例 语法: isinstance(obj1, obj2)

hasattr(), getattr(),setattr(), delattr()

         *attr()系列函数可以在各种对象下工作,不限于类(class)和实例(instances)

 

dir()与  __dict__区别:__dict__是字典结构,dir()是列表结构      ( dictionary字典   direct直接关系)

super()可以简化搜索一个合适祖先的任务,并且在调用它时,替你传入实例或类型对象。

vars()内建函数与 dir()相似,只是给定的对象参数都必须有一个__dict__属性。vars()返回一 个字典,它包含了对象存储于其__dict__中的属性(键)及值。

*****用特殊方法定制类******

两个特殊方法可以分别作为构造器和析够器的功能,分别名为 __init__()和__del__()。它们中的一些有预定 义的默认行为,而其它一些则没有,留到需要的时候去实现。这些特殊方法是 Python 中用来扩充 类的强有力的方式。它们可以实现:

模拟标准类型

重载操作符

举例--数值定制,即时间格式化显示

举例--实现__add__()特殊方法

        def __add__(self, other):

        return self.__class__(self.hr + other.hr, self.min + other.min)

        和正常情况下一样,新的对象通过调用类来创建。唯一的不同点在于,在类中,你一般不直接 调用类名,

         而是使用 self 的        __class__属性,即实例化 self 的那个类,并调用它。

举例 定制__str()__方法,以覆盖默认的行为:      ⚠️print(使用 str())、字符串对象表示(使用 repr())

    def __str__(self):
     return str(self.value)   
或     
    def __str__(self):
     return '%.2f' % self.value

为了可以让__repr__()和__str__()的输出一致,让__repr__()作为__str__()的一个别名:         __repr__ = __str__

随机序列迭代器

创建迭代器对象------⚠️一个实现了 __iter__() 和 next() 方法的类可以作为迭代器使用.

🐷在 Python 中要将某一类型的变量或者常量转换为字符串对象通常有两种方法,即str() 或者 repr()

重构__repr__和__str__区别: 把一个类的实例变成 str
__repr____str__这两个方法都是用于显示的,__str__是面向用户的,而__repr__面向开发者.想要直接输出对象(面向开发者)和使用 print 输入对象都显示的是友好提示除了重构__repr__,还要重构__str__.

self.__class__.__name__  获取实例所在类的类名

多类型类定制----举例 重构➕

私有化

Java方法使用对比

13.18 练习
13-1. 程序设计。请列举一些面向对象编程与传统旧的程序设计形式相比的先进之处。

         易维护,增加代码重复利用率,效率高、易扩展

13-2. 函数和方法的比较。函数和方法之间的区别是什么?

         函数是一段代码。通过名字调用,它能将一些数据传递进去进行处理,然后返回一些数据。也可以没有返回值

         方法也是一段代码,也通过名字来调用,但它跟一个对象相关联,方法和函数大致上是相同的,但有2个主要的不同之处:

                1.方法中的数据是隐式传递的

                 2.方法可以操作类内部的数据

13-3. 对类进行定制。写一个类,用来将浮点数值转换为金额。在本练习里,我们使用美国货币,但读者也可以自选任意货币。         

import re

class MoneyFmt(object):
    def __init__(self, value=0.0): #构造器
        self.mvalue=float(value)

    def dollarize(self):

        val = round(self.mvalue, 2)
        strval = str(val)
        if strval.startswith("-"):
            strval=strval[1:]
        else:
            strval = strval
        strval = str(strval).split('.')[0]    #取第一个.之前的内容
        strlen = len(strval)
        num = strlen%3
        ele1 = strval[:num]
        ele2 = strval[num:]
        l = re.findall(r'.{3}', ele2)
        newstr = ele1
        for i in l:
            if num == 0:
                newstr = str(i)
                num +=1
            else:
                newstr = newstr+','+str(i)
        return '$'+newstr+'.'+str(val).split('.')[1]  #取.后内容


    def update(self, newvalue=None):  #允许修改
        if newvalue is not None:
            self.mvalue = float(newvalue)


    def __repr__(self):   #显示为浮点数  直接打印变量
        return repr(self.mvalue)
        # repr = str

    def __str__(self):   #格式化显示   print函数
        if self.mvalue>0:
            sign =''
        else:
            sign ='-'
        return sign+self.dollarize()

    def __nonzero__(self):
        if self.mvalue == 0:
            return False
        else:
            return True
#Split()[0] 函数详解

# 解析:
# str.split(“o”)[0]得到的是第一个o之前的内容
# str.split(“o”)[1]得到的是第一个o和第二个o之间的内容
# str.split(“o”)[3]得到的是第三个o后和第四个o前之间的内容
# str.split("[")[0]得到的是第一个 [ 之前的内容
# 注意:[ ]内的数值必须小于等于split("")内分隔符的个数,否则会报错
# str.split("[")[1]. split("]")[0]输出的是 [ 后的内容以及 ] 前的内容

13-4. 用户注册。建立一个用户数据库(包括登录名、密码和上次登录时间戳)类(参考练习7-5和9-12),来管理一个系统,该系统要求用户在登录后才能访问某些资源。这个数据库类对用户进行管理,并在实例化操作时加载之前保存的用户信息,提供访问函数来添加或更新数据库的信息。在数据修改后,数据库会在垃圾回收时将新信息保存到磁盘。(参见__del__()).

        

from datetime import datetime
import shelve, os

class userDB(object):
    def __init__(self,dbfile):
        self.db={}
        if os.path.exists(dbfile):
            self.db=shelve.open(dbfile,'c')   #shelve库     # 参数flag的取值范围:  'r':只读打开 'w':读写访问  'c':读写访问,如果不存在则创建  'n':读写访问,总是创建新的、空的数据库文件
        self.dbfile=dbfile
        self.flag=False

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

    def login(self,user,pwd):
        if user not in self.db:
            self.flag=False
        elif self.db[user][0]==pwd:
            self.db[user][1]=datatime.now()
            self.flag=True

    def deluser(self,user):
        if self.flag:
            self.db.pop(user)
        else:
            print('login first')

    def updateuser(self,user,pwd):
        if self.flag:
            self.db[user]=[pwd,datetime.now()]
        else:
            print('login first')

13-5. 几何. 创建一个由有序数值对(x, y) 组成的Point 类,它代表某个点的X 坐标和Y 坐
标。X 坐标和Y 坐标在实例化时被传递给构造器,如果没有给出它们的值,则默认为坐标的原点。

#! /usr/env/bin python
# -*- coding:utf-8 -*-
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)

if __name__=='__main__':
    p=Point(3,4)
    print(p)
    print("p的x坐标:%d" % p.x)
    print("p的y坐标:%d" % p.y)

13-6. 几何. 创建一个直线/直线段类。除主要的数据属性:一对坐标值(参见上一个练习)外,
它还具有长度和斜线属性。你需要覆盖__repr__()方法(如果需要的话,还有__str__()方法),使得
代表那条直线(或直线段)的字符串表示形式是由一对元组构成的元组,即,((x1, y1), (x2, y2)).
总结:
      __repr__ 将直线的两个端点(始点和止点)显示成一对元组
      length 返回直线段的长度 - 不要使用"len", 因为这样使人误解它是整数。
      slope 返回此直线段的斜率(或在适当的时候返回None)

from math import sqrt

class Line(object):
    def __init__(self, x1=0, y1=0, x2=0, y2=0):
        self.x1=x1
        self.y1=y1
        self.x2=x2
        self.y2=y2
        self.length = 0
        self.slope = 0

    def getLength(self):
        self.length= sqrt((self.x1-self.x2)**2+(self.y1-self.y2)**2)
        return self.length

    def getSlope(self):
        if self.length==0:
            self.slope==None
        elif (self.x1-self.x2)==0 or (self.y1-self.y2)==0:
            self.slope==None
        else:
            self.slope=(self.y1-self.y2)/(self.x1-self.x2)
        return self.slope

    def __str__(self):
        return "((%d,%d),(%d,%d))" % (self.x1,self.y1,self.x2,self.y2)

    def __repr__(self):
        repr=str

if __name__=='__main__':
    L=Line(4,10,2,1)
    print(L)
    print('length is: %f' % L.length)
    print ('slope is: %f' % L.slope)

13-7. 数据类。提供一个time 模块的接口,允许用户按照自己给定时间的格式,比如:
“MM/DD/YY,” “MM/DD/YYYY,” “DD/MM/YY,” “DD/MM/ YYYY,” “Mon DD, YYYY,” 或是标准
的Unix 日期格式:“Day Mon DD, HH:MM:SS YYYY” 来查看日期。你的类应该维护一个日期值,并
用给定的时间创建一个实例。如果没有给出时间值,程序执行时会默认采用当前的系统时间。还包括另外一些方法:
update() 按给定时间或是默认的当前系统时间修改数据值
display() 以代表时间格式的字符串做参数,并按照给定时间的格式显示:
'MDY' ==> MM/DD/YY
'MDYY' ==> MM/DD/YYYY
'DMY' ==> DD/MM/YY
'DMYY' ==> DD/MM/YYYY
'MODYY' ==> Mon DD, YYYY
如果没有提供任何时间格式,默认使用系统时间或ctime()的格式。附加题: 把这个类和练习6-15 结合起来。

#! /usr/env/bin python
# -*- coding:utf-8 -*-

# time.time()得到的float类型的秒数
# localtime() 函数类似gmtime(),作用是格式化时间戳为本地的时间
# strftime() 函数接收 时间元组,并返回 可读字符串表示的当地时间,格式由参数format决定。
# ctime() 函数把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式.它的作用相当于 asctime(localtime(secs)). 如果参数未给或者为None的时候,将会默认time.time()为参数
# asctime() 函数接受时间元组并返回一个可读的形式为"Tue Dec 11 18:07:14 2008"(2008年12月11日 周二18时07分14秒)的24个字符的字符串

import time

class TimeFormat(object):
    def __init__(self,t=time.time()):
        self.mytime=t

    def update(self, t=time.time()):
        self.mytime=t

    def display(self, formtime=None):
        fmt={}
        fmt['MDY'] = '%m/%d/%y'
        fmt['MDYY'] = '%m/%d/%Y'
        fmt['DMY'] = '%d/%m/%y'
        fmt['DMYY'] = '%d/%m/%Y'
        fmt['MODYY'] = '%b %d,%Y'
        if formtime in fmt:

            return (time.strftime(fmt[formtime],time.localtime(self.mytime)))   

if __name__ == '__main__':
    tf = TimeFormat()
    print(tf.display())
    print(tf.display('MDY'))
    print(tf.display('MDYY'))
    print(tf.display('DMY'))
    print(tf.display('DMYY'))
    print(tf.display('MODYY'))
    tf.update(time.time()+60)
    print(tf.display())

# 执行结果如下:
# Tue Sep  8 16:37:43 2020
# 09/08/20
# 09/08/2020
# 08/09/20
# 08/09/2020
# Sep 08,2020
# Tue Sep  8 16:38:43 2020

13-8. 堆栈类。一个堆栈(Stack)是一种具有后进先出(last-in-first-out,LIFO)特性的数
据结构。你的类中应该有push()方法(向堆栈中压入一个数据项)和pop()方法(从堆栈中移出一个数据项)。还有一个叫isempty()的布尔方法,如果堆栈是空的,返回布尔值1,否则返回0;一个名叫peek()的方法,取出堆栈顶部的数据项,但并不移除它。

注意,如果你使用一个列表来实现堆栈,那么pop()方法从Python1.5.2 版本起已经存在了。那就在你编写的新类里,加上一段代码检查pop()方法是否已经存在。如果经检查pop()方法存在,就调用这个内建的方法;否则就执行你自己编写的pop()方法。你很可能要用到列表对象;如果用到它时,不需要担心实现列表的功能(例如,切片)。只要确保你写的堆栈类能够正确实现上面的两项功能就可以了。你可以用列表对象的子类或自己写个类似列表的对象,请参考示例6.2.

#! /usr/env/bin python
# -*- coding:utf-8 -*-

# 实现一个堆栈类,类中应该有push()和pop()方法,还有一个isempty()方法,如果堆栈是空的,返回布尔值1,否则返回0。

class Stack(object):
    def __init__(self, l=[]):
        self.l = l
    def isempty(self):
        if len(self.l) == 0:
            return 1
        return 0
    def push(self,element):
        print('pushed [', element,']')
        self.l.append(element)
    def pop(self):
        if self.isempty():
            print ('can not pop from an empty stack!')
        else:
            print ('removed [', self.l.pop(), ']')
    def peek(self):
        if self.isempty():
            print('can not peek from an empty stack!')
        else:
            return self.l[0]
    def viewstack(self):
        print (self.l)

if __name__=='__main__':
    s=Stack()
    s.viewstack()
    s.pop()
    s.viewstack()
    s.push(2)
    s.viewstack()

13-9. 队列类。一个队列(queue)是一种具有先进先出(first-in-first-out,FIFO)特性的数据结构。一个队列就像是一行队伍,数据从前端被移除,从后端被加入。这个类必须支持下面几种方法:
enqueue() 在列表的尾部加入一个新的元素
dequeue() 在列表的头部取出一个元素,返回它并且把它从列表中删除。

class Queue(object):
    def __init__(self, l=[]):
        self.l=l

    def enqueue(self,element):
        print ('enter queue [', element, ']')
        self.l.append(element)

    def dequeue(self):
        if self.l:
            print ('removed [', self.l.pop(0),']')
        else:
            print ('can not pop from an empty queue')

    def viewstack(self):
        print (self.l)

if __name__=='__main__':
    q=Queue([1,2,3])
    q.viewstack()
    q.enqueue(4)
    q.viewstack()
    q.dequeue()
    q.viewstack()
    q.dequeue()
    q.viewstack()

13-10. 堆栈和队列。编写一个类,定义一个能够同时具有堆栈(FIFO)和队列(LIFO)操作行为的数据结构。这个类和Perl 语言中数组相像。需要实现四个方法:
shift() 返回并删除列表中的第一个元素,类似于前面的dequeue()函数。
unshift() 在列表的头部"压入"一个新元素
push() 在列表的尾部加上一个新元素,类似于前面的enqueue()和push()方法。
pop() 返回并删除列表中的最后一个元素,与前面的pop()方法完全一样。

class FifoLifo(object):
    def __init__(self, l=[]):
        self.l=l

    def shift(self):
        """删除头"""
        if self.l:
            print ('removed [', self.l.pop(0),']')
        else:
            print('can not pop from an empty queue')

    def unshift(self,element):
        """插入头 insert"""
        print ('inserted [', element, ']')
        self.l.insert(0,element)

    def push(self,element):
        """插入尾  append"""
        print('pushed [', element, ']')
        self.l.append(element)

    def pop(self):
        """删除列表最后一个元素"""
        if self.l:
            print ('deleted [', self.l.pop(), ']')
        else:
            print('can not pop from an empty stack')

    def viewstack(self):
        print(self.l)

if __name__=='__main__':
    f=FifoLifo([1,2,3])
    f.viewstack()
    f.shift()
    f.unshift(9)
    f.viewstack()

13-11. 电子商务。
你需要为一家B2C(商业到消费者)零售商编写一个基础的电子商务引擎。你需要写一个针对顾客的类User, 一个对应存货清单的类Item, 还有一个对应购物车的类叫Cart. 货物放到购物车里,顾客可以有多个购物车。同时购物车里可以有多个货物,包括多个同样的货物。

class Item(object):
    """货品价格清单"""
    def __init__(self, product, price):
        self.product = product
        self.price = price

    def __str__(self):
        return '(%s, %.2f)' % (self.product, self.price)

    __repr__=__str__       #"""不加这行,Item无法打印"""

class Cart(object):
    """购物车  构造函数 属性"""
    def __init__(self, cartname):
        self.cartname=cartname
        self.cartlist={}   #??? 函数?方法?静态变量?

    def appenditem(self, item, count=1):
        """方法:增加数量"""
        if item not in self.cartlist:  #物品在不在购物车列表?
            self.cartlist[item]=count
        else:
            self.cartlist[item]+=count   # 物品1:5,物品2:1   -->  产品 价格:数量

    def showcart(self):
        """方法:查看"""
        for i in self.cartlist:
            print(self.cartname, i, self.cartlist[i])   #cartlist --key, cartlist[item]---value

    def deleteitem(self, item, count=1):
        """方法:减少数量"""
        if item in self.cartlist and self.cartlist[item]>=count:
            self.cartlist[item]-=count
        if self.cartlist[item]==0:
            self.cartlist.pop(item)


class User(object):
    """顾客"""
    def __init__(self, name):
        self.name = name
        self.userdb=[]

    def appendcart(self, cart):
        self.userdb.append(cart.cartname)

    def showuser(self):
        print(self.name, self.userdb)

if __name__=='__main__':
    i1=Item('Huawei', 15000)
    i2=Item('iphone',7000)
    print(i1,i2)
    i1

    c1=Cart('cart1')
    c2=Cart('cart2')
    c3=Cart('cart3')

    c1.appenditem(i1,1)
    c1.appenditem(i2,1)
    c2.appenditem(i2,3)
    c3.appenditem(i1,2)

    c1.showcart()
    c2.showcart()
    c3.showcart()

    u1=User('Amanda')
    u2=User('Lina')
    u1.appendcart(c1)
    u2.appendcart(c2)
    u2.appendcart(c3)
    u1.showuser()
    u2.showuser()


'''
((Huawei, 15000.00), (iphone, 7000.00))
('cart1', (Huawei, 15000.00), 1)
('cart1', (iphone, 7000.00), 1)
('cart2', (iphone, 7000.00), 3)
('cart3', (Huawei, 15000.00), 2)
('Amanda', ['cart1'])
('Lina', ['cart2', 'cart3'])
'''

13-12 聊天室. 你对目前的聊天室程序感到非常失望,并决心要自己写一个,创建一家新的因特网公司,获得风险投资,把广告集成到你的聊天室程序中,争取在6个月的时间里让收入翻五倍,股票上市,然后退休。但是,如果你没有一个非常酷的聊天软件,这一切都不会发生。 你需要三个类: 一个Message类,它包含一个消息字符串以及诸如广播、单方收件人等其他信息,一个User类, 包含了进入你聊天室的某个人的所有信息。为了从风险投资者那里拿到启动资金,你加了一个Room类,它体现了一个更加复杂的聊天系统,用户可以在聊天时创建单独的“聊天屋”,并邀请其他人加入。附加题: 请为用户开发一个图形化用户界面应用程序。 

class Message(object):
    def __init__(self,msg='',broadcast=False, froms='', to=''):
        self.msg=msg
        self.broadcast=broadcast
        self.froms=froms
        self.to=to

    def __str__(self):
        """广播"""
        if self.broadcast:
            return 'message %s from %s to everyone' % (self.msg, self.froms)
        else:
            return 'message %s from %s to %s' % (self.msg, self.froms, self.to)


class User(object):

    hear = {'everyone':''}      #类变量

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

    def __del__(self):
        self.__class__.hear.clear()  #dict2.clear() # 删除dict2中所有的条目 ,>>>> for key in dict2: print 'key=%s, value=%s' % (key, dict2[key])

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

    def talk(self, msg='', to=''):
        '''发送消息(广播)'''
        if to=='everyone':
            m=Message(msg,True,self.name)
            User.hear['everyone']=m     #'''把m赋值给公共变量-hear字典-的key对应-的value'''
        elif to:
            m=Message(msg,False,self.name,to)
            User.hear[to]=m
        else:
            print ('receiver can not be empty')


    def hearmsg(self):
        '''显示消息'''
        if self.name in User.hear:
            print(User.hear[self.name])
        elif User.hear['everyone']:
            print(User.hear['everyone'])
        else:
            print 'no message for %s' % self.name


    def talkroom(self, room, to='', msg=''):
        if to == 'everyone':
            m=Message(msg,True,self.name)
            room.receive(m)
        elif to:
            m=Message(msg,False,self.name,to)
            room.receive(m)
        else:
            print ('receiver can not be empty')

    def hearroom(self, m):
        print ('room %s' % m)

    def createroom(self, name, count=3):
        return Room(name, count)


 #"""room广播"""
class Room(object):
    def __init__(self, rname, count=3):
        self.rname=rname
        self.count=count
        self.userlist =[]

    def adduser(self,user):
        if len(self.userlist)<= self.count:
            self.userlist.append(user)
        else:
            print 'user number limits'

    def receive(self,m):
        if m.broadcast:
            print 'room %s' %m
        else:
            for user in self.userlist:
                if user.name in self.userlist:
                    if user.name==m.to:
                        user.hearroom(m)

if __name__=='__main__':
    u1 = User('bob', 'male', 33)
    u2 = User('jim', 'female', 31)
    u3 = User('Tom', 'female', 31)
    u1.talk('jim', 'hello')
    # u1.talk('everyone', 'hello all')
    u2.hearmsg()
    u3.hearmsg()
    room1 = u2.createroom('girls', 2)
    room1.adduser(u2)
    room1.adduser(u3)
    # room1.adduser(u1)
    u2.talkroom(room1, 'Tom', 'hello')
    u3.talkroom(room1,'everyone','hello')

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值