zoukankan      html  css  js  c++  java
  • 类的装饰器,绑定方法与非绑定方法,继承,继承背景下的属性查找

    一、类的装饰器

    BMI指数是用来衡量一个人的体重与身高对健康影响的一个指标,计算公式为

    成人的BMI数值:
    过轻:低于18.5
    正常:18.5-23.9
    过重:24-27
    肥胖:28-32
    非常肥胖, 高于32
    体质指数(BMI)=体重(kg)÷身高^2(m)
    EX:70kg÷(1.75×1.75)=22.86
    
    >>> 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)
    ...
    >>> obj=People('lili',75,1.85)
    >>> obj.bmi #触发方法bmi的执行,将obj自动传给self,执行后返回值作为本次引用的结果
    21.913805697589478
    

    使用property有效地保证了属性访问的一致性。另外property还提供设置和删除属性的功能,如下

    >>> class Foo:
    ...     def __init__(self,val):
    ...         self.__NAME=val #将属性隐藏起来
    ...     @property
    ...     def name(self):
    ...         return self.__NAME
    ...     @name.setter
    ...     def name(self,value):
    ...         if not isinstance(value,str):  #在设定值之前进行类型检查
    ...             raise TypeError('%s must be str' %value)
    ...         self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME
    ...     @name.deleter
    ...     def name(self):
    ...         raise PermissionError('Can not delete')
    ...
    >>> f=Foo('lili')
    >>> f.name
    lili
    >>> f.name='LiLi' #触发name.setter装饰器对应的函数name(f,’Egon')
    >>> f.name=123 #触发name.setter对应的的函数name(f,123),抛出异常TypeError
    >>> del f.name #触发name.deleter对应的函数name(f),抛出异常PermissionError
    

    二、绑定方法与非绑定方法

    类中定义的函数分为两大类:绑定方法和非绑定方法

    其中绑定方法又分为绑定到对象的对象方法和绑定到类的类方法。

    在类中正常定义的函数默认是绑定到对象的,而为某个函数加上装饰器@classmethod后,该函数就绑定到了类。

    绑定方法的特点:绑定给谁就应该由谁来调用,谁来调用就会将自己当做第一个参数传入

    为类中某个函数加上装饰器@staticmethod后,该函数就变成了非绑定方法,也称为静态方法。该方法不与类或对象绑定,类与对象都可以来调用它,但它就是一个普通函数而已,因而没有自动传值那么一说

    非绑定方法的特点:不与类和对象绑定,意味着谁都可以来调用,但无论谁来调用就是一个普通函数,没有自动传参的效果

    class People:
        def __init__(self,name):
            self.name = name
    
        # 但凡在类中定义一个函数,默认就是绑定给对象的,应该由对象来调用,
        # 会将对象当作第一个参数自动传入
        def tell(self):
            print(self.name)
    
        # 类中定义的函数被classmethod装饰过,就绑定给类,应该由类来调用,
        # 类来调用会类本身当作第一个参数自动传入
        @classmethod
        def f1(cls):  # cls = People
            print(cls)
    
        # 类中定义的函数被staticmethod装饰过,就成一个非绑定的方法即一个普通函数,谁都可以调用,
        # 但无论谁来调用就是一个普通函数,没有自动传参的效果
        @staticmethod
        def f2(x,y):
            print(x,y)
    
    p1 = People('egon')
    # p1.tell()
    
    # print(People.f1)
    # People.f1()
    
    # print(People.f2)
    # print(p1.f2)
    
    # People.f2(1,2)
    # p1.f2(3,4)
    
    

    三、继承

    继承是创建新类的一种方式

    新建的类称之为子类, 被继承的类称之为父类、基类、超类

    继承的特点是:子类可以遗传父类的属性

    类是用解决对象之间冗余问题的, 而继承则是来解决类与类之间冗余问题的

    在python中支持多继承

    class ParentClass1: #定义父类
        pass
    
    class ParentClass2: #定义父类
        pass
    
    class SubClass1(ParentClass1): #单继承
        pass
    
    class SubClass2(ParentClass1,ParentClass2): #多继承
        pass
    

    通过类的内置属性__bases__可以查看类继承的所有父类

    >>> SubClass2.__bases__
    (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
    

    在Python2中有经典类与新式类之分,没有显式地继承object类的类,以及该类的子类,都是经典类,显式地继承object的类,以及该类的子类,都是新式类。而在Python3中,即使没有显式地继承object,也会默认继承该类,在python3中全都是新式类。如下

    >>> ParentClass1.__bases__
    (<class ‘object'>,)
    >>> ParentClass2.__bases__
    (<class 'object'>,)
    

    继承与抽象(先抽象再继承)

    继承描述的是子类与父类之间的关系,是一种什么是什么的关系。要找出这种关系,必须先抽象再继承

    抽象即抽取类似或者说比较像的部分。

    继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。

    四、继承背景下的属性查找

    有了继承关系,对象在查找属性时,先从对象自己的--dict--中找,如果没有则去子类中找,然后再去父类中找……

    >>> class Foo:
    ...     def f1(self):
    ...         print('Foo.f1')
    ...     def f2(self):
    ...         print('Foo.f2')
    ...         self.f1()
    ... 
    >>> class Bar(Foo):
    ...     def f1(self):
    ...         print('Foo.f1')
    ... 
    >>> b=Bar()
    >>> b.f2()
    Foo.f2
    Foo.f1
    

    b.f2()会在父类Foo中找到f2,先打印Foo.f2,然后执行到self.f1(),即b.f1(),仍会按照:对象本身->类Bar->父类Foo的顺序依次找下去,在类Bar中找到f1,因而打印结果为Foo.f1

    父类如果不想让子类覆盖自己的方法,可以采用双下划线开头的方式将方法设置为私有的

    >>> class Foo:
    ...     def __f1(self): # 变形为_Foo__fa
    ...         print('Foo.f1') 
    ...     def f2(self):
    ...         print('Foo.f2')
    ...         self.__f1() # 变形为self._Foo__fa,因而只会调用自己所在的类中的方法
    ... 
    >>> class Bar(Foo):
    ...     def __f1(self): # 变形为_Bar__f1
    ...         print('Foo.f1')
    ... 
    >>> 
    >>> b=Bar()
    >>> b.f2() #在父类中找到f2方法,进而调用b._Foo__f1()方法,同样是在父类中找到该方法
    Foo.f2
    Foo.f1
    
  • 相关阅读:
    Vue.js组件理解
    Vue.js 基础知识
    JS-WEB-API 整理
    JS面向对象基础
    JS基础知识系统整理(不断更新)
    图解关于pageX,pageY,screenX,screenY,clientX,clientY的区别
    妙味JS学习记录(二)
    Ajax全接触笔记
    妙味JS学习记录(一)
    c#设计模式系列:状态模式(State pattern)
  • 原文地址:https://www.cnblogs.com/caodan01/p/14263703.html
Copyright © 2011-2022 走看看