zoukankan      html  css  js  c++  java
  • 封装的绑定与多态

    一:特性(property)

    property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

    利用这种特性可以把类的功能属性伪装成数据属性,更加方便的调用;

    为什么要用property?

    将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则。

    例如

    BMI指数(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
    
    egon=People('egon',75,1.80)
    
    egon.bmi=egon.weight / (egon.height * egon.height)
    print(egon.bmi)
    # 首先需要明确。bmi是算出来的,不是一个固定死的值,也就说我们必须编写一个功能,每次调用该功能都会立即计算一个值
    egon=People('egon',75,1.80)
    yl=People('yangli',85,1.74)
    class People:
        def __init__(self,name,weight,height):
            self.name=name
            self.weight=weight
            self.height=height
    
        def bmi(self):
            return self.weight / (self.height * self.height)
    # 但很明显人的bmi值听起来更像一个名词而非动词
    # print(egon.bmi())
    # print(yl.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 * self.height)
    # egon.weight=70
    # print(egon.bmi) 
    # print(yl.bmi)
    View Code

    调用egon.bmi本质就是触发函数bmi的执行,从而拿到其返回值。但是,虽然看上去bmi是类的实例化对象的一个属性,但这只是伪装的表现,实际上它还是一个功能,因此要注意到:

    egon.bmi=123,egon.bmi背后对应的是一个函数,所以不能赋值

    del egon.bmi,本质是一个函数,也不能删除。

    二:多态

    2.1:什么是多态?

    多态指一种食物的多种形态

    比如动物,有猫,狗,猪等多种形式

    import abc
    class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
        @abc.abstractmethod
        def talk(self):
            pass
    
    class Cat(Animal): #动物的形态之一:猫
        def talk(self):
            print('say miaomiao')
    
    class Dog(Animal): #动物的形态之二:狗
        def talk(self):
            print('say wangwang')
    
    class Pig(Animal): #动物的形态之三:猪
        def talk(self):
            print('say aoao')

    2.2: 多态性

    多态性是指不考虑实例类型的情况下使用实例

    在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。

    比如:猪,叫(),猫.叫(),猪叫是“哼哼哼”,猫叫是“喵喵喵”,虽然二者消息一样,但是执行的效果不同。

    多态性分为静态多态性和动态多态性
    静态多态性:如任何类型都可以用运算符+进行运算
    动态多态性:如下

    cat=Cat()
    dog=Dog()
    pig=Pig()
    #cat、dog、pig都是动物,只要是动物肯定有talk方法
    #于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
    cat.talk()
    dog.talk()
    pig.talk()
    #更进一步,我们可以定义一个统一的接口来使用
    def func(obj):
        obj.talk()

    2.3: 为什么要用多态性

    其实大家从上面多态性的例子可以看出,我们并没有增加什么新的知识,也就是说python本身就是支持多态性的,这么做的好处是什么呢?
    1.增加了程序的灵活性
      以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)。
    2.增加了程序额可扩展性
      通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用。

    2.4 :鸭子类型

    即如果看起来像,且叫声和走路的样子像,那么它就是一只鸭子;

    python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。

    #二者看起来都像文件,因而就可以当文件一样去用
    class TxtFile:
        def read(self):
            pass
    
        def write(self):
            pass
    
    class DiskFile:
        def read(self):
            pass
        def write(self):
            pass

    三:面向对象的绑定方法和非绑定方法

    3.1::绑定方法

    绑定给谁,谁来调用就自动将它本身当作第一个参数传入;
    在类内部定义的函数,默认就是给对象来用,而且是绑定给对象用的,称为对象的绑定方法。
    绑定对象的方法特殊之处:
      应该由对象来调用,对象来调用,会自动将对象当作第一个参数传入
    绑定到类的方法特殊之处:
      应该由类来调用,类来调用,会自动将类当作第一个参数传入
      绑定给类的方法(classmethod)
    classmehtod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数(即便是对象来调用也会将类当作第一个参数传入),python为我们内置了函数classmethod来把类中的函数定义成类方法  

    import settings
    class MySQL:
        def __init__(self,host,port):
            self.host=host
            self.port=port
    
        @classmethod
        def from_conf(cls):
            print(cls)
            return cls(settings.HOST,settings.PORT)
    
    print(MySQL.from_conf) #<bound method MySQL.from_conf of <class '__main__.MySQL'>>
    conn=MySQL.from_conf()
    
    conn.from_conf() #对象也可以调用,但是默认传的第一个参数仍然是类
    View Code

    3.2:非绑定方法

    用staticmethod装饰器装饰的方法;
    就是一个普通函数特性:既不跟类绑定,也不跟对象绑定,这意味着谁都能用,谁来用都是一个普通函数,也就是说没有自动传值的特性了。

    定义一个非绑定方法

    import hashlib
    import time
    class MySQL:
        def __init__(self,host,port):
            self.id=self.create_id()
            self.host=host
            self.port=port
        @staticmethod
        def create_id(): #就是一个普通工具
            m=hashlib.md5(str(time.time()).encode('utf-8'))
            return m.hexdigest()
    
    print(MySQL.create_id) #<function MySQL.create_id at 0x0000000001E6B9D8> #查看结果为普通函数
    conn=MySQL('127.0.0.1',3306)
    print(conn.create_id) #<function MySQL.create_id at 0x00000000026FB9D8> #查看结果为普通函数
    View Code

    非绑定方法使用实例

    import settings
    class MySQL:
        def __init__(self,host,port):
            self.host=host
            self.port=port
    
        @staticmethod
        def from_conf():
            return MySQL(settings.HOST,settings.PORT)
    
        # @classmethod #哪个类来调用,就将哪个类当做第一个参数传入
        # def from_conf(cls):
        #     return cls(settings.HOST,settings.PORT)
    
        def __str__(self):
            return '就不告诉你'
    
    class Mariadb(MySQL):
        def __str__(self):
            return '<%s:%s>' %(self.host,self.port)
    
    m=Mariadb.from_conf()
    print(m) #我们的意图是想触发Mariadb.__str__,但是结果触发了MySQL.__str__的执行,打印就不告诉你:
    
    mariadb是mysql
    View Code

    回到目录开始

  • 相关阅读:
    Linux下文件的基本操作
    conpot_usage简要说明
    const声明常量以及特点
    let变量声明以及声明特性
    盒子模型
    文本样式
    行间距
    字体的其他样式
    字体分类
    字体样式
  • 原文地址:https://www.cnblogs.com/li1992/p/8856319.html
Copyright © 2011-2022 走看看