zoukankan      html  css  js  c++  java
  • 初学Python——面向对象(二)

    一、抽象类、接口类和抽象接口

    转自博客园魏恒https://www.cnblogs.com/weihengblog/p/8528967.html

    (一)接口类

      什么是接口类?在继承中,我们可以声明某个子类继承自某基类,这个基类是个接口类,在接口类中定义了接口名(函数名)且并未实现接口的功能,子类继承接口类,并实现接口中的功能。这又叫做“接口继承”。

      接口继承实质上是规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。特点:1.做出良好的抽象类,2.规定兼容接口 3.调用者可以无需关心具体实现细节,可以一视同仁处理实现特定接口的所有对象。

    #做出一个良好的抽象
    class Payment(object):
        #规定了一个兼容接口
        def pay(self):
            pass
    
    #微信支付
    class WeChatPay(Payment):
        def pay(self,money):
            print('微信支付了%s'%money)
    
    #支付宝支付
    class AliPay(Payment):
        def pay(self,money):
            print('支付宝支付了%s'%money)
    
    #苹果支付
    class ApplePay(Payment):
        def pay(self,money):
            print('苹果支付了%s'%money)
    
    def pay(obj,money):
        obj.pay(money)
    
    weixin = WeChatPay()
    alipay = AliPay()
    applepay = ApplePay()
    
    #调用者无需关心具体实现细节,可以一视同仁的处理实现了特定接口的所有对象
    pay(weixin,100)
    pay(alipay,200)
    pay(applepay,300)
    

    (二)抽象类

    什么是抽象类?

      与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

    为什么要有抽象类?

      如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。

      比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。

      从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

      从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的

    #一切皆文件
    import abc #利用abc模块实现抽象类
    
    class All_file(metaclass=abc.ABCMeta):
        all_type='file'
        @abc.abstractmethod #定义抽象方法,无需实现功能
            def read(self):
            '子类必须定义读功能'
                pass
    
        @abc.abstractmethod #定义抽象方法,无需实现功能
            def write(self):
            '子类必须定义写功能'
                pass
    
    # class Txt(All_file):
    #     pass
    #
    # t1=Txt() #报错,子类没有定义抽象方法
    
    class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print('文本数据的读取方法')
    
        def write(self):
            print('文本数据的读取方法')
    
    class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print('硬盘数据的读取方法')
    
        def write(self):
            print('硬盘数据的读取方法')
    
    class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print('进程数据的读取方法')
    
        def write(self):
            print('进程数据的读取方法')
    
    wenbenwenjian=Txt()
    
    yingpanwenjian=Sata()
    
    jinchengwenjian=Process()
    
    #这样大家都是被归一化了,也就是一切皆文件的思想
    wenbenwenjian.read()
    yingpanwenjian.write()
    jinchengwenjian.read()
    
    print(wenbenwenjian.all_type)
    print(yingpanwenjian.all_type)
    print(jinchengwenjian.all_type)
    

    (三)抽象类和接口类

      抽象类的本质还是类,指的是一组类的相似性,包括数据属性和函数属性,而接口强调函数属性的相似性。

      抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特征,可以用来实现归一化设计。

    二、静态方法、属性方法、类方法

    1.静态方法    

      @staticmethod

      静态方法就是一个普通方法,不能访问实例变量与类变量,与类唯一的联系就是需要通过类名来调用这个方法,所以
      只是名义上归类管。私有方法不能作为静态方法,但受保护类可以作为静态方法。

    class Dog(object):
        def __init__(self,name):
            self.name = name
    
        @staticmethod # 将eat变成了静态方法,作用是将此方法断绝与类的联系,变普通函数
        def eat(self):
            print(" is eating")
    
    d = Dog("ChenRonghua")
    d.eat()
    # 这样运行会出错,要想不出错
    1.调用时,d.eat(d)。已经断绝与类的联系,"self"需要手动传入
    2.eat()方法去掉参数self
    

    2.类方法

      @classmethod

      变成类方法后,方法内只能访问类变量,不能访问实例变量。

    class Cat(object):
        name = "华仔"
        def __init__(self,name):
            self.name = name
            self.__person = None
    
        @classmethod # 类方法
        def eat(self,food):
            print('{0}吃{1}' .format(self.name,food))
    
    c1 = Cat("小猫")
    
    c1.eat("鱼")
    # 输出结果显示,类方法没有使用实例变量,使用的是类变量
    

    3.属性方法

      @property

      可以把一个方法变成静态属性。也就是将原本的方法变成了静态属性,不能传参数,不能修改属性值,也不能删除

    先来看一下

    class Cat(object):
        name = "华仔"
        def __init__(self,name):
            self.name = name
            self.person = None
    
        @property
        def talk(self):
            print("{0} is talking with {1}".format(self.name,self.person))
    
    c1 = Cat("小猫")
    
    c1.talk
    #输出:小猫 is talking with None
    

       这时,想要对self.person进行修改是不可以的,会报错。

      若非要修改,也是可以通过特殊方法来修改的,

    #在上述代码的基础上加上如下代码(在原eat方法的下面,类的里面) 
        @talk.setter   # 修改属性方法的值需要这样做
        def talk(self,person):
            print("{0} is talking with {1}".format(self.name,person))
            self.person = person
    
    c1.talk = "Jack"
    c1.talk   # 再次访问,发现真正修改了它
    # 输出:
    小猫 is talk with Jack
    

      同样,若非要删除,也可以

        @talk.deleter  # 删除属性方法的值需要这样做
        def talk(self):
            del self.person
            print("已删除talk")
    
    del c1.talk
    c1.talk # 删除后再访问运行出错!
    

      这时相信你会有个疑问,为什么还需要属性方法的存在呢?直接定义一个静态变量不就行了吗?属性方法和属性有什么不同呢?

      属性方法的本质还是方法(函数),只是变得特殊了,我们知道属性方法具有以下两点特征:

        1.属性方法内可以对内部属性进行访问

        2.属性方法不能被随意修改删除,防止误改误删,保证了安全性。

      在实际应用中,有这样的需求:已经写好了具有特定功能的方法,作用是返回一个数值。而要经过一系列的动作才能得到这个值,这显然不是变量可以完成的。用户调用它时只需要像对待静态变量一样就可以得到一个值,中间的过程用户不需要关心。

    三、反射

      在实际应用中,我们需要根据用户输入来做出相应的工作,比如输入1调用a方法,输入2调用b方法,输入2调用c方法.....,这些我们可以用if else分支语句来判断并执行,但显而易见,如果用户输入的种类非常多,if else语句的代码量就非常可观了,不美观,也不便于维护。怎么办呢?

      1.需要用到反射函数hasattr()来判断对象是否有这个方法

      2.如果有这个方法,则可以用getatter()函数来找到对象方法的内存地址

      3.加上括号即可调用  

    class Dog(object):
        def __init__(self,name):
            self.name = name
        
        def eat(self,name):
            print("{0} is eating {1}".format(self.name,name))
    
    def bulk(self):
        print("{0} is yelling".format(self.name))
    
    d = Dog("Alex")
    
    
    chioce = input("请输入操作:").strip()
    If hasattr(d,chioce) == True:
        fun = getattr(d,chioce)
        a = input("what does the dog want eating ?")
        fun(a)
    else:
        setattr(d,chioce,bulk) # 将类外部的函数加入了类的内部
        v = getattr(d,chioce)
        v(d)
    

      so,什么叫反射?通过字符串来运行或修改程序运行时的状态、属性、方法

      一共有四个方法:

        1.hasattr(obj,str)  obj是对象,str是字符串,判断对象是否有此方法(属性),返回True或False

        2.getattr(obj,str)  obj是对象,str是字符串,返回对象中方法(属性)的内存地址

        3.setattr(x,y,z)     (x,y=z)x是对象,y是字符串,z是方法的内容,设置一个新的方法(属性),或修改方法(属性)

        4.delattr(obj,str)  obj是对象,str是字符串,删除属性(不能删除原有的方法?)

    chioce = input("请输入操作:").strip()
    setattr(d,chioce,18) # 创建属性并赋值
    print(d.talk)
    setattr(d,"name","Chen") # 修改已存在的name属性
    print(d.name)
    
    delattr(d,"name") # 删除name属性
    #print(d.name)  # 报错
    
    # 输入:talk
    输出:
    18
    Chen
    Chen is yelling
    

     四、动态导入模块

      如何使用字符串导入模块呢?

      之前讲过一个方法,使用__import__()内置函数;第二个方法是动态导入模块

    • __import__()内置函数

    1 '''导入lib包,调用包下aa模块的text()函数'''
    2 b = __import__("lib.aa")
    3 b.aa.text()
    4 "这是解释器内部用的,一般不建议用这个,建议用下面的"
    5 #output:
    6 from lib.aa.text()
    '''导入lib包,调用包下aa模块的text()函数'''
    b = __import__("lib.aa")
    b.aa.text()
    "这是解释器内部用的,一般不建议用这个,建议用下面的"
    #output:
    from lib.aa.text()
    
    • 动态导入
    vimport importlib
    c = importlib.import_module("lib.aa")
    "导入lib.aa。b 代表 lib.aa "
    c.text()
    #output:
    from lib.aa.text()
  • 相关阅读:
    Java中的Graphics2D类基本使用教程
    JSP中页面向Action传递参数的几种方式
    中英文统计
    numpy数据集练习 ----------sklearn类
    IDEA在jsp页面写out.print()代码报错
    Tag文件的创建与应用
    Intellij部署Tomcat问题
    单例测试模式中【饿汉式】与【懒汉式】的区别
    java中类与方法叙述正确的是
    下列关于异常处理的描述中,错误的是()。
  • 原文地址:https://www.cnblogs.com/V587Chinese/p/9304199.html
Copyright © 2011-2022 走看看