• 12 new方法和单例、定制访问函数、装饰器


    new方法和单例、定制访问函数、装饰器

    • 上节课作业解答

    # 通过多重继承方法,分别定义出动物,人类,和和荷兰人三种类
    class Animal(object):
        def __init__(self, name):
            self.name = name
    ​
        def eat(self):
            print('%s正在吃东西' % self.name)
    ​
        def breath(self):
            print('%s正在呼吸' % self.name)
    ​
    ​
    class Person(Animal):
        def __init__(self, name, money):
            super().__init__(name)
            self.money = money
    ​
        def speak(self):
            print('%s说他有%s人民币' % (self.name, self.money))
    ​
    ​
    class Fulan(Person):
        def eat(self):
            print('弗兰人%s不仅爱吃辣,而且爱吃槟榔' % self.name)
    ​
        def speak(self):
            print('福兰人%s正在blablabla讲弗兰话。' % self.name)
    ​
    ​
    juhao = Fulan('句号', 23)
    juhao.breath()
    juhao.eat()
    juhao.speak()
    ​
    ​
    #拼接一个Spiderman
    class Spider(Animal):
        def climb(self):
            print('%s正在攀岩' % self.name)
    ​
        def tusi(self):
            print('%s正在吐丝' % self.name)
    ​
    ​
    class Spiderman(Person, Spider):
        pass
    ​
    ​
    Spiderman = Spiderman('Spiderman', 10)
    Spiderman.tusi()
    Spiderman.climb()
    Spiderman.eat()
    Spiderman.breath()
    ​
    #说明:
    1. 调用父类的两种方法:
    Animal.__init__(self.name)
    super().__init__(name)
    2. 不能直接调用__init__,且__init__只能有一个
    以上运行结果
    
    
    句号正在呼吸
    弗兰人句号不仅爱吃辣,而且爱吃槟榔
    福兰人句号正在blablabla讲弗兰话。
    Spiderman正在吐丝
    Spiderman正在攀岩
    Spiderman正在吃东西
    Spiderman正在呼吸

    一、魔术方法补充

    所有的函数都是类(对象)

    魔术方法示例:(__方法__)

    (一) 引入
    a = 'hahaha'
    b = '12'
    print(b + a)
    ​
    # 等效于
    print(b.__add__(a))
    ​
    # 运行结果
    # 12hahaha
    # 12hahaha
    (二) 魔术方法在类中的使用
    • 示例__add__

      # 添加其他属性

    # 魔术方法在类中的使用
    class Rectangle(object):
        def __init__(self, length, width):
            self.length = length
            self.width = width
    ​
        def get_area(self):
            return self.length * self.width
    ​
        def __add__(self, other):  
            add_length = self.length + other.length
            add_width = self.width + other.width
            return add_length, add_width
    • 示例__str__ __repr__

      str(面向使用者,提供简洁有用信息)

      repr(面向开发者,提供接近创建时的信息,让开发者可以通过复制粘贴来重建对象)

      直接在交互界面中,直接返回值和print()所使用的(str和repr)魔术方法不同

    # str和repr原理
    # 例 1
        def __str__(self):
            return 'length is %s, width is %s' % (self.length, self.width)
        
        def __repr__(self):
            return '长是%s,宽是%s'% (self.length, self.width)
    ​
        def __call__(self, *args, **kwargs):
            print('我正在被调用')
            
    rec1 = Rectangle(10, 20)
    rec2 = Rectangle(30, 40)
    rec1()
    print(rec1 + rec2)
    print(str(rec1))   # (如果不写rec1会返回函数体<……>)
    print(repr(rec1))  # (如果不写rec1会返回函数体<……>)
    # 运行结果
    我正在被调用
    (40, 60)
    length is 10, width is 20
    长是10,宽是20
    ​
    # 注: 直接在交互界面中,直接返回值和print()使用的(str和repr)魔术方法不同
    # 例 2
    a = '1,2,3'
    a
    '1,2,3'
    print(a)
    1,2,3# 说明:
    函数可以直接调用,但是类必须要使用call魔术方法才可以直接调用
    (三) 简单魔术方法(了解)
    __class__查看类名
    __base__ 查看继承的父类
    __mro__ 追根溯源到object,super是基于mro实现的
    __bases__ 查看继承的全部父类
    __dict__ 查看全部属性,返回属性和属性值键值对形式
    __doc__ 查看对象文档,即类中的注释(用引号注释的部分)(注释不能被继承)
    __dir__ 查看全部属性和方法(等效于dir)

    二、new方法和单例

    在初始化函数init之前执行,创建实例

    # __new__
    a = Rectangle.__new__()
    Rectangle.__init__(a)  
    ​
    ​
    # 单例模式(节省内存)
    class Esrth(object):
        def __new__(cls, *args, **kwargs):
            if not hasattr(cls,'instance'):
                cls.instance = super().__new__(cls)
            return cls.instance
    ​
        def __init__(self):
            self.name = '单例'
    ​
    a = Esrth()
    print(id(a))
    b = Esrth()
    print(id(b))  # 把e覆盖了
    #运行结果
    3072614988
    3072614988# 说明:
    1. 在以上例子中可以看见两个实例的id其实是相同的,意味着这两个实例其实引用的是同一个实例,(只占一个内存)是一个实例的不同名字
    2. 其中self代表实例本身,cls代表类本身hasattr判断类中有没有('')参数
    3. 如果没有就调用object中new方法
    
    
    (一)__new__方法class Hero(object):
    ​
        def __init__(self):
            print('这是init方法')
    ​
        def __new__(cls):
            print('这个cls是:%s' % cls)
            print('这是new方法')
            return object.__new__(cls)
    ​
    ​
    garen = Hero()
    ​
    运行结果:
    这个cls是:<class '__main__.Hero'>
    这是new方法
    这是init方法
    ​
    说明:
    四个点理解__new__方法
    1、__new__方法是在 类 创建实例 的时候自动调用的。
    2、实例是通过类里面的__new__方法是在 类 创建出来的。
    3、先调用__new__方法创建实例,再调用 __init__方法初始化实例4、__new__方法,,后面括号里的cls代表的是类本身
    在上面的例子中,我们可以看到创建实例的时候,自动调用了__new__,方法和__init__方法,并且是先调用的__new__再调用的__init__方法,打印 cls 的时候显示的这个Hero类
    (二)单例模式:
    class Hero(object):
        __instance = None   # 定义一个私有属性__instance等于None
    def __new__(cls):
            if cls.__instance == None:      # 然后我们判断它是不是等于None,如果等于None,我们调用父类的方法创建一个实例对象,并把返回的对象赋值给 __instance,并且返回__instance
                cls.__instance = object.__new__(cls)
                return cls.__instance
            else:       #  如果__instance不等于None,那就说明已经创建了对象我们直接把__instance返回去。
                return cls.__instance
    ​
    ​
    a = Hero()
    b = Hero()
    print(id(a))
    print(id(b))
    ​
    打印结果:
    3072101708
    3072101708# 说明:
    单例模式实现的原理:通过重写__new__方法,让__new__只能进行一次实例创建。
    在上面的例子中,我们可以看到两个实例的ID是相同的,意味着第二次创建的时候,并没有真正的去创建,而是引用的第一次创的实例,同一个实例的不同名字

    三、定制访问函数

    (一) 常见方法
    作用方法返回
    hasattr(re,'length') 返回bool值
      getattr(re,'length') 返回属性值
      b.__getattribute__('length') 返回全部属性值
    setattr(b,'length',6)  
      b.__setattr__('length',5)  
    b.aaa = 1  
      setattr(b,'leg',2)  
      b.__setattr__('leg',3)  
    delattr(b,'leg')  
      b.__delattr__('leg')  
      del b  
    
    
    # 实例:
    class Rectangle(object):
        def __init__(self,length,width):
            self.length = length
            self.width = width
    ​
        def area(self):
            return self.length * self.width
    ​
    a = Rectangle(10,20)
    print(a.area())
    #
    print(hasattr(a,'length'))      # 返回bool值
    print(getattr(a,'length'))      # 返回属性值
    print(a.__getattribute__('width'))      # 返回属性值
    #
    setattr(a,'length',5)
    a.__setattr__('width',5)
    print(a.length)
    print(a.width)
    #
    a.aaa = 1
    setattr(a,'bbb',2)
    a.__setattr__('ccc',3)
    print(a.aaa)
    print(a.bbb)
    print(a.ccc)
    #
    delattr(a,'ccc')
    a.__delattr__('bbb')
    del a
    # print(a.ccc)
    # print(a.bbb)
    # print(a.length)
    ​
    打印结果:
    200
    True
    10
    20
    5
    5
    1
    2
    3
    注:print(hasattr(实例rec1,属性'length'))等效于print(rec1.__hasattr__('name'))
    (二) 举例
    # 定制属性访问
    # 例 __getattr__
    ​
    re = Rectangle(3,4)
    ​
    def __getattr__(self,item):
        print('no attribute')
    # 当属性不存在时,若定义了此方法则调用此方法,若存在则返回原值
    (三) 了解__getattribute__
    b.__getattribute__('length')
    # 正常调用返回属性值,属性值不存在,调用__getattr__未定义时会报错

    四、装饰器

    (一) 引入
    def eat():
        return '小明在吃东西'def boom():
        return eat() + '并且爆炸了'print(boom())
    ​
    #等效于
    def boom(func):
        return func() + '并且爆炸了'
    ​
    xiaoming = boom(eat)
    print(xiaoming)
    ​
    # 运行结果
    小明在吃东西并且爆炸了
    小明在吃东西并且爆炸了
    (二) 改善

    可以看到输出时方式不一样,可以修改为以下操作

    # 例 1
    def boom(func):
        def new_func():
            return func() + '并且爆炸了'
        return new_func
    ​
    xiaoming = boom(eat)
    print(xiaoming())
    ​
    #运行结果
    小明在吃东西并且爆炸了
    
    
    # 例 2
    def eat2(name):
        return '小明和%s在吃东西' % name
    ​
    def boom2(func2):
        def new_func2(name):
            return func2(name) + '并且爆炸了'
        return new_func2
    ​
    eat2 = boom2(eat2)
    print(eat2('小红'))
    ​
    #运行结果
    小明和小红在吃东西并且爆炸了
    (三) 装饰器
    例1
    def boom3(func3):
        def new_func3(name):
            return func3(name) + '并且爆炸了'
        return new_func3
    ​
    ​
    @boom3
    def eat3(name):
        return '小明和%s在吃东西' % name
    ​
    print(eat3('小红'))
    ​
    # 运行结果
    小明和小红在吃东西并且爆炸了
    例2
    def f1(fu):
        def func2():
            print('这是装饰器功能代码')
            fu()
    ​
        return func2
    ​
    ​
    @f1
    def func():
        print('这是基础功能代码')
    ​
    ​
    func = f1(func)  # 等同@f1
    ​
    func()
    ​
    打印结果:
    这是装饰器功能代码
    这是装饰器功能代码
    这是基础功能代码
    (四) 其他装饰器
    class Rectangle:
        def __init__(self, length, width):
            self.length = length
            self.width = width
    ​
        def area(self):
            areas = self.length * self.width
            return areas
    ​
    # 像访问属性一样
        @property
        def areal(self):
            return self.width *self.length
    ​
    ​
    #静态方法
        @staticmethod
        def func(): #如果写了self在调用时会报错
            print('staticmethod func')
    ​
    ​
    ​
    #类方法
        @classmethod
        def show(cls): #cls代表类本身 如果加上self在调用时要把实例传入
            print(cls)
            print('show fun')
            
            
    ​
            
    # 用类做装饰器
    class TestClass(object):
        def __init__(self, func):
            self.func = func
    ​
        def __call__(self, *args, **kwargs):
            print('1234')
            return self.func()
    ​
    @TestClass
    def shuzi():
        print('5678')
    ​
    shuzi()
    ​
    ​
    # 运行结果
    1234
    5678
    (五) 装饰器参考
    from datetime import datetime
    ​
    ​
    def run_time(func):
        def new_func(*args,**kwargs):
            start_time = datetime.now()
            print('程序开始时间:%s' % start_time)
            func(*args, **kwargs)
            end_time = datetime.now()
            print('程序结束时间:%s' % end_time)
            print('程序总共执行时间:%s' % (end_time - start_time))
    ​
        return new_func()
    ​
    print(datetime.now())
    ​
    # 运行结果
    2018-04-13 17:10:39.332348
  • 相关阅读:
    Java 多线程分析 (六) ----三种方式实现Thread
    图论--深度优先遍历DFS
    图---邻接链表建立
    打印从1到n位数(防止数据溢出)
    Java 基础知识理解
    l链表的反转
    RecordList
    ArrayList
    git仓库相关知识02-远程仓库
    git仓库相关知识01-安装和基本命令
  • 原文地址:https://www.cnblogs.com/zcmq/p/9114111.html
Copyright © 2020-2023  润新知