python类的继承和单例模式 singleton、运算符重载

@[toc]

设计模式

  • 开闭模式 open close principle
    对扩展开放,对修改关闭
  • 里氏代换原则 liskov substitution principle
    任何基类可以出现的地方,派生类一定可以出
    现– 即基类可被派生类替换
  • 依赖倒转原则 Dependence Inversion Principle
    针对接口编程,依赖抽象而不依赖具体
  • 接口隔离原则(Interface Segregation Principle)
    使用多个隔离的接口,比使用单个接口要好
    降低类之间的耦合度
  • 最小知道原则(Demeter Principle)
    一个实体应当尽量少地与其他实体发生作用
    系统功能模块应相对独立
  • 合成复用原则(Composite Reuse Principle)
    尽量使用合成/聚合的方式,而不是使用继承

单例模式

全局只有一个实例

  • 应用场景
    输入法和全局配置参数

<font color=#03a3e3>该实现方式在多线程场景下不安全

class Singleton:
    _instance=None
    def __init__(self, name, volume):
        self.name=name
        self.volume=volume

    def __new__(cls,name,volume):
        if not Singleton._instance:
        #if not hasattr(Singleton,'_instance'):
            Singleton._instance=object.__new__(cls)
            Singleton.__init__(Singleton._instance,name,volume)
        return Singleton._instance

slist=[Singleton('z',100) for i in range(10)]
for s in slist:
    print(hex(id(s)),end='\t')
    print(f"{s.name}\t{s.volume}")
0x1ca17bce310   z       100
0x1ca17bce310   z       100
0x1ca17bce310   z       100
0x1ca17bce310   z       100
0x1ca17bce310   z       100
0x1ca17bce310   z       100
0x1ca17bce310   z       100
0x1ca17bce310   z       100
0x1ca17bce310   z       100
0x1ca17bce310   z       100

类的继承

继承其他类的类称为派生类(derived class)
被其他类继承的类称为这些类的基类(base
class)

class DerivedClassName(BaseClassName):
    <statement-1>
    ……
    <statement-N>
  • 作用域
    基类必须与派生类定义在一个作用域内
    可以用表达式指定模块
class DerivedClassName(modname.BaseClassName):
    pass
  • 派生类
    派生类定义的执行过程与基类类似
    如果在类中找不到请求调用的属性会搜索基类
    如果基类由别的类派生而来,则会递归式搜索
  • 继承的检查
    isinstance() 用于检查实例类型
    issubclass() 用于检查类继承
  • 多继承
    python支持多继承
    派生类可以同时继承多个基类
class People:
    """
    人的类,定义人相关的一些基本信息如姓名,身高,年龄等。

    """
    def __init__(self,name,height,age):
        self.__name=name
        self.__height=height
        self.__age=age

    def get_name(self):
        return self.__name

    def set_name(self,name):
        self.__name=name

    def get_height(self):
        return self.__height

    def set_height(self,height):
        self.__height=height

    def get_age(self):
        return self.__age

    def set_age(self,age):
        self.__age=age

    def print_info(self):
        print('in People')
        print('Name:{},Age:{},Height:{}'.\
            format(self.get_name(),self.get_age(),self.get_height()))

    def __add__(self,other):
        return self.get_height()+other.get_height()

class Speaker():
    """
    演讲家类
    """
    def __init__(self,topic):
        self.__topic=topic

    def get_topic(self):
        return self.__topic

    def set_topic(self,topic):
        self.__topic=topic

    def speak(self):
        print('in Speaker')
        print("speak topic is {}".format(self.get_topic()))
       
class Student(People,Speaker):
    """
    学生类,继承人的类,同时添加一些新的属性,并覆盖方法
    
    """
    def __init__(self,name,height,age,topic,ID,major):
        People.__init__(self,name,height,age)
        Speaker.__init__(self,topic)
        self.__ID=ID
        self.__major=major

    def get_ID(self):
        return self.__ID

    def set_ID(self,ID):
        self.__ID=ID

    def get_major(self):
        return self.__major;

    def set_major(self,major):
        self.__major=major

    def print_info(self):
        print('ID:{}, Name:{}, Major:{}, Age:{}, Height:{}'.\
            format(self.get_ID(),self.get_name(),self.get_major(), self.get_age(),self.get_height()))

    def speak(self):
        #super(Student,self).print_info()
        #super(Student,self).speak()
        super().print_info()
        super().speak()

p1=People('z',175,40)
s1=Student('zjc',175,35,'python',33060828,'cs')
print(p1+s1)

#s1.print_info()
s1.speak()

People.print_info(s1)
350
in People
Name:zjc,Age:35,Height:175
in Speaker
speak topic is python     
in People
Name:zjc,Age:35,Height:175
class DerivedClassName(Base1,Base2,Base3):
    <statement-1>
    ……
    <statement-N>

需要注意圆括号中基类的顺序:<font color=#03a3e3>从左到右搜索<font>

多继承会导致菱形 diamond关系:有至少一个基类可以从子类经由多个继承路径到达
基类方法可能被多次调用

super()方法

防止重复访问,每个基类只调用一次

通过子类实例对象课调用父类已被覆盖
慎用多继承(二义性)

class BaseClass:
    num_base_calls=0
    def call_me(self):
        print("calling method on Base Class")
        BaseClass.num_base_calls+=1

class LeftSubclass(BaseClass):
    num_left_calls=0
    def call_me(self):
        BaseClass.call_me(self)
        #super().call_me()
        print("calling method on Left Subclass")
        LeftSubclass.num_left_calls+=1

class RightSubclass(BaseClass):
    num_right_calls=0
    def call_me(self):
        BaseClass.call_me(self)
        #super().call_me()
        print("calling method on Right Subclass")
        RightSubclass.num_right_calls+=1

class Subclass(LeftSubclass,RightSubclass):
    num_sub_calls=0
    def call_me(self):
        LeftSubclass.call_me(self)
        RightSubclass.call_me(self)
        #super().call_me()
        print("print calling method on Subclass")
        Subclass.num_sub_calls+=1
s=Subclass()
s.call_me()
#print(s)

print("\tsub_call:{}\n\
    left_call:{}\n\
    right_call:{}\n\
    base_call:{}".format(Subclass.num_sub_calls,LeftSubclass.num_left_calls,RightSubclass.num_right_calls,BaseClass.num_base_calls))
calling method on Base Class
calling method on Left Subclass 
calling method on Base Class    
calling method on Right Subclass
print calling method on Subclass
        sub_call:1
        left_call:1
        right_call:1
        base_call:2

运算符重载 operator overload

– 对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
– 运算符重载不能改变其本来寓意
– 运算符重载只是一种 “语法上的方便” (sugar)
– 是一种函数调用的方式

class Point:
    def __init__(self,x,y):
        self.x=x
        self.y=y
    def __add__(self,other):
        return Point(self.x+other.x,self.y+other.y)
    def __sub__(self,other):
        return Point(self.x-other.x,self.y-other.y)
    def __str__(self):
        return "({},{})".format(self.x,self.y)
    def __lt__(self,other):
        return self.x<other.x
    def __gt__(self,other):
        return self.x>other.x
    def __le__(self,other):
        return self.x<=other.x
    def __ge__(self,other):
        return self.x>=other.x
    def __eq__(self,other):
        return self.x==other.x
    def __ne__(self,other):
        return self.x!=other.x
    def __call__(self):
        '''
        Point类的实例可调用,也称可调用对象
        '''
        print('我不是函数,别调了')


p1=Point(1,2)
p2=Point(3,4)
print(p1+p2)
p3=p2-p1
print(p3)
print(p1<p2)
plist=[p1,p2,p3]
plist=sorted(plist,reverse=True)
print('\n'.join([str(p) for p in plist]))
p1()
p2()
p3()
(4,6)
(2,2)
True
(3,4)
(2,2)
(1,2)
我不是函数,别调了
我不是函数,别调了
我不是函数,别调了

类的专有方法

方法 作用
init 初始化函数,在生成对象时调用
repr 返回对象的字符串表达式
getitem 按照索引获取值
call 实例对象可调用,可调用对象,可以有参数
str 提供一个不正式的字符串表示,使得对象可用print输出
iter,next 迭代
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容