zoukankan      html  css  js  c++  java
  • Python基础之面向对象进阶一

      一、isinstance(obj,cls)和issubclass(sub,super)

      1、isinstance(obj,cls)检查obj是否是类 cls 的对象

    class A:
        pass
    
    obj = A() #实例化对象obj
    isinstance(对象名,类名)#语法
    print(isinstance(obj,A)) #isinstance函数返回的是布尔值,True,则obj,是A产生的对象
    print(isinstance(object,A)) #同上,反之,为不是。
    ---------------输出结果-------------------
    True
    False

      2、issubclass(sub, super)检查sub类是否是 super 类的派生类或子类

    class A: #定义父类
        pass
    
    class B(A): #定义子类,继承A
        pass
    
    issubclass(子类名,父类名) #语法
    print(issubclass(B,A)) #返回的也是布尔值,True为真,则B,是A的子类,反之,不是
    -------------输出结果------------------
    True
    

      二、反射

      1、什么是反射:

      反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自

    省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp

    和面向对象方面取得了成绩。  

      2、反射的简单含义:

        1、通过类名获得类的实例对象

        2、通过方法名得到方法,实现调用

      3、python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用

    反射)。

      反射即想到4个内置函数分别为:hasattr、getattr、setattr、delattr  获取成员、检查成员、设置成员、删除成员下面

    逐一介绍先看例子:

    class motorcycle: #仅限二轮摩托
        feature = "两个轱辘" #相对而言
        def __init__(self,brand,price):
            self.brand = brand
            self.price = price
        def advance(self): #都有前进的技能
            print("%s,出发了!"%self.brand)
        def stop(self): #都有减速,停车功能
            print("%s,减速了!"%self.brand)
    
    m1 = motorcycle("春风",28800) #实例化对象m1
    

      3.1、hasattr(obj,"name"):检测obj里是否含有"name"属性

    #检测是否含有某属性
    print(hasattr(m1,"feature")) #检测对象m1是否有类的数据属性
    print(hasattr(m1,"brand")) #检测m1里是否有"brand"这个数据属性
    print(hasattr(m1,"advance")) #检测m1里是否有"advance"这个绑定方法
    print(hasattr(motorcycle,"feature")) #一切皆对象,加测类里面是否有"feature"这个数据属性
    print(hasattr(motorcycle,"stop")) #一切皆对象,检测类里面是否有"stop"这个函数属性
    print(hasattr(m1,"abcd")) #检测到没有这个"abcd"的时候,此时,会返回False
    ----------------------输出结果-------------------
    True
    True
    True
    True
    True
    False
    

      3.2、getattr(obj,"name"):获取obj里的"name"的属性

    #获取某属性
    n = getattr(m1,"brand") #获取m1的品牌属性,并赋值给n
    print(n) #打印n
    n1 = getattr(motorcycle,"feature") #一切皆对象,获取类的数据属性,并赋值给n1
    print(n1) #打印n1
    n2 = getattr(m1,"feature") #获取对象m1的类的特征,并赋值给n2
    print(n2) #打印n2
    n3 = getattr(m1,"advance") #获取m1的绑定方法,并赋值给n3
    n3() #现在n3就是m1的绑定方法,加括号就能调用
    n4 = getattr(motorcycle,"stop") #获取类的函数属性,并赋值给n4
    n4(m1) #因为n4是类的函数属性,so,调用的时候要传参
    #getattr(m1,"abcd") #没有abcd"会报错
    print(getattr(m1,"abcd","不存在啊!")) #没有"abcd"会打印后面的字符串
    -----------------输出结果--------------------
    春风
    两个轱辘
    两个轱辘
    春风,出发了!
    春风,减速了!
    不存在啊!

      3.3、setattr(obj,"name",content):设置obj里的"name"的属性

    #设置某属性
    setattr(m1,"displacement",650) #新增m1的"displacement"数据属性
    setattr(m1,"show_brand",lambda self: self.brand+"666") #新增m1的函数属性
    setattr(m1,"price",26800) #春风做活动,回馈车友,减价2000,修改m1的价格
    setattr(motorcycle,"show_brand",lambda self:self.brand+"666") #新增类的函数属性
    setattr(motorcycle,"feature","两个轱辘,还有三个轱辘的") #修改类的特征
    print(m1.show_brand(m1)) #注意,此时"show_brand"就是一个普通函数,需要传一个参数进去
    print(motorcycle.show_brand(m1)) #类名.新增的函数名加括号调用,因为是函数属性,so,要传参
    print(m1.__dict__) #打印对象m1的所有的属性
    print(motorcycle.__dict__) #打印类motorcycle的所有的属性
    -------------------输出结果--------------------------
    春风666
    春风666
    {'brand': '春风', 'price': 26800, 'displacement': 650, 'show_brand':
     <function <lambda> at 0x0000000002113E18>}
    {'__module__': '__main__', 'feature': '两个轱辘,还有三个轱辘的',
     '__init__': <function motorcycle.__init__ at 0x00000000025FA950>, 
    'advance': <function motorcycle.advance at 0x00000000025FA9D8>,
     'stop': <function motorcycle.stop at 0x00000000025FAA60>, '__dict__': 
    <attribute '__dict__' of 'motorcycle' objects>, '__weakref__': <attribute 
    '__weakref__' of 'motorcycle' objects>, '__doc__': None, 'show_brand': 
    <function <lambda> at 0x00000000025FAAE8>}
    

      3.4、delattr(obj,"name"):删除obj里的"name"的属性

    #删除某属性
    delattr(m1,"displacement") #删除m1的"displacement"数据属性
    delattr(m1,"show_brand") #删除m1的"show_brand"的函数属性
    delattr(motorcycle,"show_brand") #删除类的函数属性
    print(m1.__dict__) #打印对象m1的所有的属性
    print(motorcycle.__dict__) #打印类motorcycle的所有的属性
    --------------------输出结果-------------------------
    {'brand': '春风', 'price': 28800}
    {'__module__': '__main__', 'feature': '两个轱辘', '__init__': 
    <function motorcycle.__init__ at 0x000000000291A950>,
     'advance': <function motorcycle.advance at 0x000000000291A9D8>, 
    'stop': <function motorcycle.stop at 0x000000000291AA60>,
     '__dict__': <attribute '__dict__' of 'motorcycle' objects>,
     '__weakref__': <attribute '__weakref__' of 'motorcycle' objects>,
     '__doc__': None}
    

      4、为什么用反射之反射的好处

      好处一:实现可插拔机制

      可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思

    ?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能。

    #类代码同上
    if hasattr(m1,"advance"): #判断m1里是否含有"advance"属性,有就执行里面的代码
        func = getattr(m1,"advance") #有就实现此行代码,这样就不会出现异常,将获取到的内存地址给func
        func() #调用次方法
    print("继续其他逻辑") #就算没有也不会影响下面代码的执行,实现了可插拔机制
    --------------------输出结果---------------------
    春风,出发了!
    继续其他逻辑

      好处二:动态导入模块(基于反射当前模块成员)

    #模块(mokuai)的内容:
    x = 123 #变量x
    class A: #定义一个类
        def aaa(self): #类A的函数属性aaa
            print("from aaa")
    def bbb(): #定义一个函数bbb
        print("from bbb")
    

      动态导入模块:

    import  importlib
    this_module = importlib.import_module("mokuai")
    #语法就是this_module.属性名
    print(this_module.x) #打印模块里变量x的值,
    a = this_module.A() #类A实例化对象a
    a.aaa() #对象a调用绑定方法
    this_module.bbb() #调用函数bbb
    ----------------输出结果--------------------
    123
    from aaa
    from bbb
    

      三、__setattr__,__getattr__,__delattr__

    class foo:
        def __init__(self,name):
            self.name = name
        def __setattr__(self, key, value): #添加/修改属性时,会触发它的执行
            if not isinstance(value,str):
                raise TypeError("must be str")
            #self.key = value #注意:这样就无限递归了
            self.__dict__[key] = value
        def __getattr__(self, item): #当属性不存在的时候,会触发它的执行
            print("不存在----->%s"%item)
        def __delattr__(self, item): #删除属性时,会触发它的执行
            # print("不能被删除!") #强制不让删除
            #del self.item #注意:这样就无限递归了
            self.__dict__.pop(item) #真正删除的方法
    
    f1 = foo("michael")  # 实例化对象f1
    #调用__setattr__
    print(f1.__dict__) #打印f1的属性字典
    f1.age = "18" #"18"必须是str,赋值就会触发__setattr__的执行
    print(f1.__dict__) #打印f1的属性字典
    
    #调用__getattr__
    print(f1.abcd) #此时abcd是不存在的,没有这个属性,会返回None
    
    #调用__delattr__
    del f1.age #删除属性
    print(f1.__dict__) #打印f1的属性字典
    -------------------输出结果-----------------------
    {'name': 'michael'}
    {'name': 'michael', 'age': '18'}
    不存在----->abcd
    None
    {'name': 'michael'}
    

      四、二次加工标准类型(包装)

      包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型

    来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的

    方式进行二次加工)。

    #基于继承的原理,来定制自己的数据类型(继承标准类型)
    class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和insert
        def append(self, p_object): #自己加工追加的方法
            if not isinstance(p_object,int): #加上条件,不是int就抛出异常
                raise TypeError("must be int") #返回提示输入类型
            #self.append(p_object) #注意:这样就无限递归了
            super().append(p_object) #此时才会完成追加
    
        def insert(self, index, p_object): #自己加工指定位置插入的方法
            if not isinstance(p_object,int): #加上条件,不是int就抛出异常
                raise TypeError("must be int") #返回提示输入类型
            super().insert(index,p_object) #此时才会完成插入
    
    l1 = List([0,1,2]) #实例化对象l1
    print(l1) #打印列表l1
    l1.append(3) #对象l1追加元素3,注意必须是int
    print(l1) #打印列表l1
    # l1.append("5") #此时会抛出异常,"5"不是int
    l1.insert(0,-1) #在下标0的位置,插入元素-1,注意元素的类型
    l1.insert(5,4) #在下标5的位置,插入元素4,注意元素的类型
    print(l1) #打印列表l1
    print(l1.index(4)) #获取元素的下标,没有派生出自己的方法的时候,会继承父类的方法
    --------------------输出结果------------------------
    [0, 1, 2]
    [0, 1, 2, 3]
    [-1, 0, 1, 2, 3, 4]
    5
    

      授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有

    产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给

    对象的默认属性。

      实现授权的关键点就是覆盖__getattr__方法。

    import time
    class Open: #open是一个函数,不是类,不能用继承,so,用另一种方式:授权
        def __init__(self,file_path,m="r",endoce="utf8"):
            self.file = open(file_path,mode=m,encoding=endoce) #获取文件句柄
            self.file_path = file_path #文件路径
            self.mode = m #文件打开模式
            self.encoding = endoce #文件的编码方式
    
        def write(self,line): #写入文件
            t = time.strftime("%Y-%m-%d %X") #获取时间格式
            self.file.write("%s ---> %s"%(t,line)) #前面加上时间,按格式写入
        def __getattr__(self, item): #当方法不存在的时候,会触发它的执行
            return getattr(self.file,item) #获取文件其他的方法,并返回给对象
    
    f1 = Open("a.txt","w") #实例化对象f1,创建文件a.txt,以w模式
    f1.write("1、你好,我摩旅去了!
    ") #按自己加工的方法写入内容
    f1.write("2、你好,我摩旅去了!
    ") #按自己加工的方法写入内容
    f1.write("3、你好,我摩旅去了!
    ") #按自己加工的方法写入内容
    f1.close() #关闭文件
    f2 = Open("a.txt","r") #实例化对象f2,查看文件a.txt,以r模式
    print(f2.read()) #打印输出a.txt的文件内容
    f2.seek(0) #刚看完,光标走到最后位置了。要想再看,就得把光标调到最开始位置
    print("-->:",f2.read()) #加上标识,再看一遍
    f2.close() #关闭文件
    -----------------输出结果------------------
    2017-04-24 18:30:57 ---> 1、你好,我摩旅去了!
    2017-04-24 18:30:57 ---> 2、你好,我摩旅去了!
    2017-04-24 18:30:57 ---> 3、你好,我摩旅去了!
    
    -->: 2017-04-24 18:30:57 ---> 1、你好,我摩旅去了!
    2017-04-24 18:30:57 ---> 2、你好,我摩旅去了!
    2017-04-24 18:30:57 ---> 3、你好,我摩旅去了!
    

      授权小练习:

    #要求:
    # 基于授权定制自己的列表类型,要求定制的自己的__init__方法,
    # 定制自己的append:只能向列表加入字符串类型的值
    # 定制显示列表中间那个值的属性(提示:property)
    # 其余方法都使用list默认的(提示:__getattr__加反射)
    
    class list: #定义一个类list
        def __init__(self,li):
            self.li = li
        def append(self,value): #自己加工追加的方法
            if not isinstance(value,str): #加上条件,不是str就抛出异常
                raise TypeError("must be str") #返回提示输入类型
            self.li.append(value) #追加到列表中
        @property
        def pro(self): #加上装饰器的pro,获取属性
            index = len(self.li)//2 #获取列表中间的索引
            return self.li[index] #返回中间的元素
    
        def __getattr__(self, item): #当方法不存在的时候,会触发它的执行
            return getattr(self.li,item) #获取列表其他的方法,并返回给对象
    
    l1 = list([1,2,3]) #实例化对象l1,新建列表
    print(l1.li) #查看列表的内容
    # l1.append(4) #此时会抛出异常,因为不是str类型
    l1.append("4") #往l1列表追加内容
    print(l1.li) #打印追加后的列表
    print(l1.pro) #pro加property后,调用不用加括号了,跟获取数据属性一样
    print(l1.index(2)) #自己没有定义的方法,会触发__getattr__,使用list其
    他的方法,这里查看元素2的索引是多少
    ---------------------输出结果---------------------
    [1, 2, 3]
    [1, 2, 3, '4']
    3
    1
    

      

  • 相关阅读:
    使用Netty4实现基本的消息分发
    【Netty官方文档翻译】引用计数对象(reference counted objects)
    nio复习总结
    redis tutorail
    服装设计
    linux nat网络配置
    关闭linux退格键和vi发出的嘟嘟声
    CentOS/Linux 网卡设置 IP地址配置
    WCF Security基本概念(转载)
    WCF使用net.tcp寄宿到IIS中(转)
  • 原文地址:https://www.cnblogs.com/Michael--chen/p/6753570.html
Copyright © 2011-2022 走看看