zoukankan      html  css  js  c++  java
  • 第八章 Python——面向对象编程

    目录

    一、面向对象编程

    二、类class与对象object

    三、继承与派生

    四、多态与多态性(抽象类)

    五、封装

    六、绑定方法

    七、反射

    八、与面向对象有关的内置函数

    九、自定义内置方法

    十、元类

    十一、单例模式

    一、面向对象编程

    【面向过程编程】
    核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么然后干什么。。。
    基于该思想编写程序好比在设计一条流水线,是一种机械式的思维方式

    优点:复杂的问题流程化、进而简单化
    缺点:扩展性差

    【面向对象编程】
    核心对象二字,对象是特征与技能的结合体
    基于该思想编写程序就好比是在创造一个世界,你就是这个世界的上帝,是一种上帝式的思维方式

    优点:可扩展性强
    缺点:编程的复杂度要高于面向过程

    二、类class与对象object

    (一)类class

    什么是类(what):

    类可以理解为种类、分类、类别

    对象是特征与技能的结合体,类是一系列对象相似的特征与技能的结合体
    强调:站的角度不同,总结出的类是截然不同的

    在现实世界中:先有的一个个具体存在的对象,然后随着人类文明的发展才了分类的概念
    在程序中:必须先定义类,后调用类来产生对象

    站在老男孩选课系统的角度,先总结现实世界中的老男孩的学生对象
    对象1:
    特征:
    学校='oldboy'
    姓名='耗哥'
    年龄=18
    性别='male'
    技能:
    选课

    对象2:
    特征:
    学校='oldboy'
    姓名='猪哥'
    年龄=17
    性别='male'
    技能:
    选课

    对象3:
    特征:
    学校='oldboy'
    姓名='帅翔'
    年龄=19
    性别='female'
    技能:
    选课

    站在老男孩选课系统的角度,先总结现实世界中的老男孩学生类
    老男孩学生类:
    相似的特征:
    学校='oldboy'
    相似的技能
    选课
    #在程序中
    #1、先定义类
    class OldboyStudent:
        school='oldboy'
    
        def choose_course(self):
            print('is choosing course')
    
    #类体代码会在类定义阶段就立刻执行,会产生一个类的名称空间
    
    # 类的本身其实就是一个容器/名称空间,是用来存放名字的,这是类的用途之一
    print(OldboyStudent.__dict__)
    print(OldboyStudent.__dict__['school'])
    print(OldboyStudent.__dict__['choose_course'])
    OldboyStudent.__dict__['choose_course']()
    
    #
    print(OldboyStudent.school) 
    #OldboyStudent.__dict__['school']
    print(OldboyStudent.choose_course) #OldboyStudent.__dict__['choose_course']
    
    #
    OldboyStudent.country='China' #OldboyStudent.__dict__['country']='China'
    
    #
    OldboyStudent.country='CHINA' #OldboyStudent.__dict__['country']='China'
    
    #
    del OldboyStudent.school
    print(OldboyStudent.__dict__)
    
    
    
    #2、后调用类产生对象,调用类的过程,又称为类的实例化,实例化的结果称为类的对象/实例
    stu1=OldboyStudent() 
    # 调用类会得到一个返回值,该返回值就是类的一个具体存在的对象/实例
    stu2=OldboyStudent() 
    # 调用类会得到一个返回值,该返回值就是类的一个具体存在的对象/实例
    stu3=OldboyStudent() 
    # 调用类会得到一个返回值,该返回值就是类的一个具体存在的对象/实例

     

    (二)对象object

    什么是对象(what):

    对象本质也就是一个名称空间而已,对象名称空间是用存放对象自己独有的名字/属性,而类中存放的是对象们共有的属性

    #类的属性应用与实例化
    class OldboyStudent:
        school='oldboy'
    
    
        def __init__(obj, name, age, male): #会在调用类时自动触发
            obj.name = name #stu1.name='耗哥'
            obj.age = age  #stu1.age=18
            obj.sex = male #stu1.sex='male'
    
        def choose_course(self):
            print('is choosing course')
    
    #调用类时发生两件事
    #1、创造一个空对象stu1
    #2、自动触发类中__init__功能的执行,将stu1以及调用类括号内的参数一同传入
    stu1=OldboyStudent('耗哥',18,'male')
    #OldboyStudent.__init__(stu1,'耗哥',18,'male')
    stu2=OldboyStudent('猪哥',17,'male')
    stu3=OldboyStudent('帅翔',19,'female')
    
    print(stu1.__dict__)
    print(stu2.__dict__)
    print(stu3.__dict__)
    #属性查找
    #需求:查看生成了多少次对象
    
    class OldboyStudent:
        school='oldboy'
        count=0
    
        def __init__(self, x, y, z): #会在调用类时自动触发
            self.name = x #stu1.name='耗哥'
            self.age = y  #stu1.age=18
            self.sex = z #stu1.sex='male'
            OldboyStudent.count+=1
    
        def choose_course(self):
            print('is choosing course')
    
    
    # 先从对象自己的名称空间找,没有则去类中找,如果类也没有则报错
    stu1=OldboyStudent('耗哥',18,'male')
    stu2=OldboyStudent('猪哥',17,'male')
    stu3=OldboyStudent('帅翔',19,'female')
    
    print(OldboyStudent.count)
    print(stu1.count)
    print(stu2.count)
    print(stu3.count)
    属性查找顺序

     Tips:

    ①类名称空间中定义的数据属性和函数属性都是共享给所有对象用的。对象名称空间中定义的只有数据属性,而且时对象所独有的数据属性。

    ②类中定义的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数而已,意味着需要完全遵循函数的参数规则,该传几个值就传几个参数。

    (三)初识绑定方法

    什么是绑定方法(what):

    类中定义的函数是共享给所有对象的,对象也可以使用,而且是绑定给对象用的。

    绑定效果:

    绑定给谁,就应该由谁来调用,谁来调用就会将谁当作第一个参数自动传入。

    Tips:

    ①类中定义的函数,类确实可以使用,但其实类定义的函数大多情况下都是绑定给对象用的,所以在类中定义的函数都应该自带一个参数self。

    (四)类即类型

    在python3中统一了类与类型的概念,类就是类型。

    class OldboyStudent:
        school='oldboy'
    
        def __init__(self, name, age, male): #会在调用类时自动触发
            self.name = name #stu1.name='耗哥'
            self.age = age  #stu1.age=18
            self.sex = male #stu1.sex='male'
    
        def choose_course(self,x):
            print('%s is choosing course' %self.name)
    
    stu1=OldboyStudent('耗哥',18,'male')
    l=[1,2,3] #l=list([1,2,3])
    print(type(l))
    l.append(4) #list.append(l,4)
    list.append(l,4)
    print(l)

    三、继承与派生

    (一)继承

    什么是继承(what):

    继承是一种新建类的方式,新建的类称为子类,被继承的类称为父类
    继承的特性是:子类会遗传父类的属性
    强调:继承是类与类之间的关系

    为什么用继承(why):

    继承的好处就是可以减少代码的冗余。

    怎么用继承(how):

    在python中支持一个类同时继承多个父类
    在python3中
    如果一个类没有继承任何类,那默认继承object类
    在python2中:
    如果一个类没有继承任何类,不会继承object类

    (二)菱形继承问题

    什么是菱形继承(what):

    当一个子继承多个父类时,多个父类最终继承了同一个类,称之为菱形继承。

    菱形继承问题划分:

    【新式类】
    但凡继承了object的类以及该类的子类,都是新式类。

    查找属性方法:广度优先查找
    【经典类】
    没有继承object的类以及该类的子类,都是经典类。

    查找属性方法:深度优先查找

    在python3中都是新式类,只有在python2中才区别新式类与经典类。

    Tips:python内置mro()(C3算法)查找广度优先顺序。

    (三)派生

    什么是派生(what):

    子类中新定义的属性,子类在使用时始终以自己的为准。

    对象查找属性的顺序:对象自己-》对象的类-》父类-》父类。。。

    (四)子类中调用父类的方法

    在子类派生出的新功能中重用父类功能的方式有两种:
    1、指名道姓访问某一个类的函数:该方式与继承无关

    # 方式一:与继承无关
    #指名道姓法,直接用:类名.函数名
    class OldboyPeople:
        school = 'oldboy'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    class OldboyStudent(OldboyPeople):
        def __init__(self,name,age,sex,stu_id):
            OldboyPeople.__init__(self,name,age,sex)
            self.stu_id=stu_id
    
        def choose_course(self):
            print('%s is choosing course' %self.name)

    2、严格用继承关系查找

    super()会得到一个特殊的对象,该对象就是专门用来访问父类中的属性的(按照继承的关系)
    super().__init__(不用为self传值)
    Tips:
    super的完整用法是super(自己的类名,self),在python2中需要写完整,而python3中可以简写为super()

    # 方式二:严格以来继承属性查找关系
    
    class OldboyPeople:
        school = 'oldboy'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    class OldboyStudent(OldboyPeople):
        def __init__(self,name,age,sex,stu_id):
            # OldboyPeople.__init__(self,name,age,sex)
            super(OldboyStudent,self).__init__(name,age,sex)
            self.stu_id=stu_id
    
        def choose_course(self):
            print('%s is choosing course' %self.name)
    
    
    stu1=OldboyStudent('猪哥',19,'male',1)
    print(stu1.__dict__)

    (五)组合

     什么是组合(what):

    组合就是一个类的对象具备某一个属性,该属性的值是指向另外外一个类的对象。

    为什么用组合(why):

    组合也是用来解决类与类直接代码冗余问题的。

    如何用组合(how):

    class Course:
        def __init__(self,name,period,price):
            self.name=name
            self.period=period
            self.price=price
    
        def tell_info(self):
            msg="""
            课程名:%s
            课程周期:%s
            课程价钱:%s
            """ %(self.name,self.period,self.price)
            print(msg)
    
    class OldboyPeople:
        school = 'oldboy'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    class OldboyStudent(OldboyPeople):
        def __init__(self,name,age,sex,stu_id):
            OldboyPeople.__init__(self,name,age,sex)
            self.stu_id=stu_id
    
        def choose_course(self):
            print('%s is choosing course' %self.name)
    
    class OldboyTeacher(OldboyPeople):
    
        def __init__(self, name, age, sex, level):
            OldboyPeople.__init__(self,name,age,sex)
            self.level=level
    
        def score(self,stu,num):
            stu.score=num
            print('老师[%s]为学生[%s]打分[%s]' %(self.name,stu.name,num))
    
    # 创造课程
    python=Course('python全栈开发','5mons',3000)
    linux=Course('linux运维','5mons',800)
    
    
    # 创造学生与老师
    stu1=OldboyStudent('猪哥',19,'male',1)
    tea1=OldboyTeacher('egon',18,'male',10)
    
    
    # 将学生、老师与课程对象关联/组合
    stu1.course=python
    tea1.course=linux
    
    stu1.course.tell_info()
    tea1.course.tell_info()

    四、多态与多态性(抽象类)

    什么是多态(what):

     多态指的是同一种事物的多种形态

    水-》冰、水蒸气、液态水
    动物-》人、狗、猪

    为什么要用多态(why):

    多态性:
    继承同一个类的多个子类中有相同的方法名
    那么子类产生的对象就可以不用考虑具体的类型而直接调用功能

    如何用多态(how):

    #抽象类

    import
    abc class Animal(metaclass=abc.ABCMeta): @abc.abstractmethod def speak(self): pass @abc.abstractmethod def eat(self): pass # Animal() #强调:父类是用来指定标准的,不能被实例化 class People(Animal): def speak(self): print('say hello') def eat(self): pass class Dog(Animal): def speak(self): print('汪汪汪') def eat(self): pass class Pig(Animal): def speak(self): print('哼哼哼') def eat(self): pass peo1=People() dog1=Dog() pig1=Pig()

    Tips:python推崇的是鸭子类型,只要你叫的声音像鸭子,并且你走路的样子也像鸭子,那你就是鸭子。

    class Disk:
        def read(self):
            print('disk read')
    
        def write(self):
            print('disk wirte')
    
    
    class Process:
        def read(self):
            print('process read')
    
        def write(self):
            print('process wirte')
    
    
    class File:
        def read(self):
            print('file read')
    
        def write(self):
            print('file wirte')
    
    
    
    obj1=Disk()
    obj2=Process()
    obj3=File()
    鸭子类型

      

    五、封装

    什么是封装(what):

    封:属性对外是隐藏的,但对内是开放的
    装:申请一个名称空间,往里装入一系列名字/属性

    为什么要封装(why):

    封装数据属性的目的:
      首先定义属性的目的就是为了给类外部的使用使用的,
      隐藏之后是为了不让外部使用直接使用,需要类内部开辟一个接口
      然后让类外部的使用通过接口来间接地操作隐藏的属性。
    精髓在于:我们可以在接口之上附加任意逻辑,从而严格控制使用者对属性的操作

    封装函数属性:
      首先定义属性的目的就是为了给类外部的使用使用的,
      隐藏函数属性是为了不让外不直接使用,需要类内部开辟一个接口
      然后在接口内去调用隐藏的功能
    精髓在于:隔离了复杂度

    如何封装(how):

    如何隐藏:在属性前加上__开头

    1、 这种隐藏仅仅只是一种语法上的变形操作
    2、 这种语法上的变形只在类定义阶段发生一次,因为类体代码仅仅只在类定义阶段检测一次
    3、 这种隐藏是对外不对内的,即在类的内部可以直接访问,而在类的外则无法直接访问,原因是 在类定义阶段,类体内代码统一发生了一次变形

    4、 如果不想让子类的方法覆盖父类的,可以将该方法名前加一个__开头

    #需求:通过封装控制修改对象的方式
    class People:
        def __init__(self,name,age):
            self.__name=name
            self.__age=age
    
        def tell_info(self):
            print('%s:%s' %(self.__name,self.__age))
    
        def set_info(self,name,age):
            if type(name) is not str:
                # print('用户名必须为str类型')
                # return
                raise TypeError('用户名必须为str类型')
    
            if type(age) is not int:
                # print('年龄必须为int类型')
                # return
                raise TypeError('年龄必须为int类型')
            self.__name=name
            self.__age=age
    
    peo1=People('egon',18)
    peo1.set_info('egon',19)
    peo1.tell_info()

    六、property与绑定方法

    (一)特性property

     property装饰器用于将被装饰的方法伪装成一个数据属性,在使用时可以不用加括号而直接引用。

    #需求:计算BMI
    class People:
        def __init__(self,name,weight,height):
            self.name=name
            self.weight=weight
            self.height=height
    
        @property
        def bmi(self):
            return self.weight / (self.height ** 2)
    
    peo1=People('egon',75,1.8)
    
    peo1.height=1.85
    print(peo1.bmi)
    #property内置方法
    class People:
        def __init__(self,name):
            self.__name=name
    
        @property # 查看obj.name
        def name(self):
            return '<名字是:%s>' %self.__name
    
        @name.setter #修改obj.name=值
        def name(self,name):
            if type(name) is not str:
                raise TypeError('名字必须是str类型')
            self.__name=name
    
        @name.deleter #删除del obj.name
        def name(self):
            # raise PermissionError('不让删')
            print('不让删除')
            # del self.__name
    
    peo1=People('egon')
    # print(peo1.name)
    
    # print(peo1.name)
    
    # peo1.name='EGON'
    # print(peo1.name)
    
    del peo1.name
    class People:
        def __init__(self,name):
            self.__name=name
    
    
        def tell_name(self):
            return '<名字是:%s>' %self.__name
    
        def set_name(self,name):
            if type(name) is not str:
                raise TypeError('名字必须是str类型傻叉')
            self.__name=name
    
        def del_name(self):
            print('不让删除傻叉')
    
        name=property(tell_name,set_name,del_name)
    
    
    peo1=People('egon')
    
    print(peo1.name)
    peo1.name='EGON'
    print(peo1.name)
    del peo1.name
    property内置方法古老写法

     (二)绑定方法与非绑定方法

    1、绑定方法
    特性:绑定给谁就应该由谁来调用,谁来调用就会将谁当作第一个参数自动传入
    《《《精髓在于自动传值》》》

    1、绑定方法分为两类:
    1.1 绑定给对象方法
    在类内部定义的函数(没有被任何装饰器修饰的),默认就是绑定给对象用的
    1.2 绑定给类的方法(@classmethod):
    在类内部定义的函数如果被装饰器@classmethod装饰,
    那么则是绑定给类的,应该由类来调用,类来调用就自动将类当作第一个参数自动传入

    2、非绑定方法(@staticmethod)
    类中定义的函数如果被装饰器@staticmethod装饰,那么该函数就变成非绑定方法
    既不与类绑定,又不与对象绑定,意味着类与对象都可以来调用
    但是无论谁来调用,都没有任何自动传值的效果,就是一个普通函数

    3、应用
    如果函数体代码需要用外部传入的类,则应该将该函数定义成绑定给类的方法
    如果函数体代码需要用外部传入的对象,则应该将该函数定义成绑定给对象的方法
    如果函数体代码既不需要外部传入的类也不需要外部传入的对象,则应该将该函数定义成非绑定方法/普通函数

    '''
    settings.py文件内容
    IP = '10.13.24.245
    PORT = 3306
    '''
    
    #需求:
    一种新的实例化方式:从配置文件中读取配置完成实例化
    class Mysql:
        def __init__(self,ip,port):
            self.uid=self.create_uid()
            self.ip=ip
            self.port=port
    
        def tell_info(self):
            print('%s:%s' %(self.ip,self.port))
    
        @classmethod
        def from_conf(cls):
            return cls(settings.IP, settings.PORT)
    
        @staticmethod
        def func(x,y):
            print('不与任何人绑定')
    
        @staticmethod
        def create_uid():
            return uuid.uuid1()
    
    # 默认的实例化方式:类名(..)
    obj=Mysql('10.10.0.9',3307)

     七、反射

    什么是反射(what):

    通过字符串来操作类或者对象的属性。

    如何使用反射(how):

    hasattr
    getattr
    setattr
    delattr

    class People:
        country='China'
        def __init__(self,name):
            self.name=name
    
        def eat(self):
            print('%s is eating' %self.name)
    
    peo1=People('egon')
    
    
    print(hasattr(peo1,'eat')) #peo1.eat
    
    print(getattr(peo1,'eat')) #peo1.eat
    print(getattr(peo1,'xxxxx',None))
    
    setattr(peo1,'age',18) #peo1.age=18
    print(peo1.age)
    
    print(peo1.__dict__)
    delattr(peo1,'name') #del peo1.name
    print(peo1.__dict__)

    八、与面向对象有关的内置函数

    class Foo:
        pass
    
    obj=Foo()
    
    print(isinstance(obj,Foo))
    
    # 在python3中统一类与类型的概念
    d={'x':1} #d=dict({'x':1} #)
    
    print(type(d) is dict)
    print(isinstance(d,dict))
    
    issubclass()
    
    
    class Parent:
        pass
    
    class Sub(Parent):
        pass
    
    print(issubclass(Sub,Parent))
    print(issubclass(Parent,object))

    九、自定义内置方法

    # 1、__str__方法
    class People:
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        #在对象被打印时,自动触发,应该在该方法内采集与对象self有关的信息,然后拼成字符串返回
        def __str__(self):
            # print('======>')
            return '<name:%s age:%s>' %(self.name,self.age)
    obj=People('egon',18)
    obj1=People('alex',18)
    print(obj)  #obj.__str__()
    print(obj)  #obj.__str__()
    print(obj)  #obj.__str__()
    print(obj1)  #obj1.__str__()
    
    
    d={'x':1} #d=dict({'x':1})
    print(d)
    
    
    #2、__del__析构方法
    # __del__会在对象被删除之前自动触发
    class People:
        def __init__(self,name,age):
            self.name=name
            self.age=age
            self.f=open('a.txt','rt',encoding='utf-8')
    
        def __del__(self):
            # print('run=-====>')
            # 做回收系统资源相关的事情
            self.f.close()
    
    obj=People('egon',18)
    
    print('')

     十、元类

    什么是元类(what):

    在python中一切皆对象,那么我们用class关键字定义的类本身也是一个对象
    负责产生该对象的类称之为元类,即元类可以简称为类的类
    class Foo: # Foo=元类()
      pass

    为什么用元类(why):

    元类是负责产生类的,所以我们学习元类或者自定义元类的目的:
    是为了控制类的产生过程,还可以控制对象的产生过程。

    如何用元类(how):

    #储备知识:内置函数exec的用法
    cmd="""
    x=1
    def func(self):
        pass
    """
    class_dic={}
    exec(cmd,{},class_dic)
    
    print(class_dic)
    内置函数exec

    创建类的两种方法:

    大前提:如果说类也是对象的化,那么用class关键字的去创建类的过程也是一个实例化的过程
    该实例化的目的是为了得到一个类,调用的是元类

    方式一:用的默认的元类type

    #2.1 方式一:用的默认的元类type
    class People: #People=type(...)
        country='China'
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def eat(self):
            print('%s is eating' %self.name)
    
    print(type(People))
    
    #2.1.1 创建类的3个要素:类名,基类,类的名称空间
    class_name='People'
    class_bases=(object,)
    class_dic={}
    class_body="""
    country='China'
    def __init__(self,name,age):
        self.name=name
        self.age=age
    
    def eat(self):
        print('%s is eating' %self.name)
    """
    exec(class_body,{},class_dic)
    
    #准备好创建类的三要素
    print(class_name)
    print(class_bases)
    print(class_dic)
    
    #People=type(类名,基类,类的名称空间)
    People1=type(class_name,class_bases,class_dic)
    print(People1)
    obj1=People1('egon',18)
    print(People)
    obj=People('egon',18)
    
    obj1.eat()
    obj.eat()

    方式二:用的自定义元类

    #2.2 方式二:用的自定义的元类
    class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
        def __init__(self,class_name,class_bases,class_dic):
            print(self) #现在是People
            print(class_name)
            print(class_bases)
            print(class_dic)
            super(Mymeta,self).__init__(class_name,class_bases,class_dic) #重用父类的功能
    
    # 分析用class自定义类的运行原理(而非元类的的运行原理):
    #1、拿到一个字符串格式的类名class_name='People'
    #2、拿到一个类的基类们class_bases=(obejct,)
    #3、执行类体代码,拿到一个类的名称空间class_dic={...}
    #4、调用People=type(class_name,class_bases,class_dic)
    class People(object,metaclass=Mymeta): #People=Mymeta(类名,基类们,类的名称空间)
        country='China'
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def eat(self):
            print('%s is eating' %self.name)
    
    
    # 应用:自定义元类控制类的产生过程,类的产生过程其实就是元类的调用过程
    
    class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
        def __init__(self,class_name,class_bases,class_dic):
            if class_dic.get('__doc__') is None or len(class_dic.get('__doc__').strip()) == 0:
                raise TypeError('类中必须有文档注释,并且文档注释不能为空')
            if not class_name.istitle():
                raise TypeError('类名首字母必须大写')
            super(Mymeta,self).__init__(class_name,class_bases,class_dic) #重用父类的功能
    
    class People(object,metaclass=Mymeta): #People=Mymeta('People',(object,),{....})
        """这是People类"""
        country='China'
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def eat(self):
            print('%s is eating' %self.name)
    #3 储备知识:__call__
    class Foo:
        def __call__(self, *args, **kwargs):
            print(self)
            print(args)
            print(kwargs)
    
    
    obj=Foo()
    #
    # # 要想让obj这个对象变成一个可调用的对象,需要在该对象的类中定义一个方法__call__方法
    # # 该方法会在调用对象时自动触发
    obj(1,2,3,x=1,y=2)
    
    
    4、自定义元类来控制类的调用的过程,即类的实例化过程
    class Mymeta(type):
    
        def __call__(self, *args, **kwargs):
            # print(self) # self是People
            # print(args)
            # print(kwargs)
            # return 123
    
            # 1、先造出一个People的空对象
            obj=self.__new__(self)
            # 2、为该对空对象初始化独有的属性
            # print(args,kwargs)
            self.__init__(obj,*args,**kwargs)
    
            # 3、返回一个初始好的对象
            return obj
    
    
    class People(object,metaclass=Mymeta):
        country='China'
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def eat(self):
            print('%s is eating' %self.name)
    
        def __new__(cls, *args, **kwargs):
            print(cls)
            # cls.__new__(cls) # 错误
            obj=super(People,cls).__new__(cls)
            return obj
    
    # 分析:调用Pepole的目的
    #1、先造出一个People的空对象
    #2、为该对空对象初始化独有的属性
    # obj1=People('egon1',age=18)
    # obj2=People('egon2',age=18)
    # print(obj1)
    # print(obj2)
    
    obj=People('egon',age=18)
    print(obj.__dict__)
    print(obj.name)
    obj.eat()
    class Mymeta(type):
        def __init__(self,class_name,class_bases,class_dic):
            #控制类Foo的创建
            super(Mymeta,self).__init__(class_name,class_bases,class_dic)
    
        def __call__(self, *args, **kwargs):
            #控制Foo的调用过程,即Foo对象的产生过程
            obj = self.__new__(self)
            self.__init__(obj, *args, **kwargs)
            obj.__dict__={'_%s__%s' %(self.__name__,k):v for k,v in obj.__dict__.items()}
    
            return obj
    
    class Foo(object,metaclass=Mymeta):  # Foo=Mymeta(...)
        def __init__(self, name, age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
    
    obj=Foo('egon',18,'male')
    print(obj.__dict__)
    练习:通过原来控制Foo的调用过程,隐藏属性

    十一、单例模式

    什么是单例模式(what):

    基于某种方法实例化多次得到实例是同一个

    为什么用单例模式(why):

    当实例化多次得到的对象中存放的属性都一样的情况,应该将多个对象指向同一个内存,即同一个实例。

    如何用单例模式(how):

    方式一:绑定classmethod装饰器

    import settings
    
    class Mysql:
        __instacne=None
    
        def __init__(self,ip,port):
            self.ip=ip
            self.port=port
    
        @classmethod
        def from_conf(cls):
            if cls.__instacne is None:
                cls.__instacne=cls(settings.IP,settings.PORT)
            return cls.__instacne
    # obj=Mysql('1.1.1.10',3306)
    
    obj1=Mysql.from_conf()
    obj2=Mysql.from_conf()
    obj3=Mysql.from_conf()
    
    print(obj1)
    print(obj2)
    print(obj3)
    
    obj4=Mysql('10.10.10.11',3307)

    方式二:自定义一个装饰器控制单例模式

    import settings
    def singleton(cls):
        cls.__instance=cls(settings.IP,settings.PORT)
        def wrapper(*args,**kwargs):
            if len(args) == 0 and len(kwargs) == 0:
                return cls.__instance
            return cls(*args,**kwargs)
        return wrapper
    
    @singleton #Mysql=singleton(Mysql) #Mysql=wrapper
    class Mysql:
        def __init__(self,ip,port):
            self.ip=ip
            self.port=port
    
    
    obj1=Mysql() #wrapper()
    obj2=Mysql() #wrapper()
    obj3=Mysql() #wrapper()
    print(obj1 is obj2 is obj3)
    print(obj1)
    print(obj2)
    print(obj3)
    obj4=Mysql('1.1.1.4',3308)
    print(obj4)

    方式三:控制元类类实现单例模式 

    import settings
    
    class Mymeta(type):
        def __init__(self,class_name,class_bases,class_dic): #self=Mysql
            super(Mymeta,self).__init__(class_name,class_bases,class_dic )
            self.__instance=self.__new__(self) #造出一个Mysql的对象
            self.__init__(self.__instance,settings.IP,settings.PORT) #从配置文件中加载配置完成Mysql对象的初始化
    
            # print(self.__instance)
            # print(self.__instance.__dict__)
    
        def __call__(self, *args, **kwargs): #self=Mysql
            if len(args) == 0 and len(kwargs) == 0:
                return self.__instance
    
            obj=self.__new__(self)
            self.__init__(obj,*args,**kwargs)
            return obj
    
    
    
    class Mysql(object,metaclass=Mymeta): #Mysql=Mymeta(...)
        def __init__(self,ip,port):
            self.ip=ip
            self.port=port
    
    
    obj1=Mysql()
    obj2=Mysql()
    obj3=Mysql()
    obj4=Mysql('10.10.10.11',3308)
    
    print(obj1)
    print(obj2)
    print(obj3)
    print(obj4)
  • 相关阅读:
    Linux提供哪些功能
    C++——重载原理分析
    C++——多维数组动态开辟与释放
    C++——异常处理
    C++——流类库和输入/输出
    C++——virtual function
    C++——虚函数表解析
    C++——多态实现原理分析
    Python基础——__name__变量
    DNS服务——智能域名解析、镜像Web站点、直接域名泛域名
  • 原文地址:https://www.cnblogs.com/neymargoal/p/9225035.html
Copyright © 2011-2022 走看看