• 面向对象高级(上)


    1 判断类型和子类

      判断对象是否是属于某个类的

    isinstance(对象名, 类名)

        注意: 如果是它的父类, 同样也返回True; 但是 (父类的对象, 子类) 返回的是Fale

      查看父类, 注意是使用类名而不是对象

    类名.__bases__

      判断是否是某个类的子类

    issubclass(子类名, 父类名)

    2 反射

      反射是指程序可以访问、检测和修改它本身状态或行为的一种能力  

    2.1 反射参数

      可以通过不同的字符串来反射不同的参数, 进而进行一定的操作; 或者反射一些函数来执行

      在Python中主要是使用内置函数hasattr, getattr, setattr, delattr三个函数

      hassattr(), 判断对象或者类是否具有摸个参数, 第一个参数是类或者对象, 第二个参数是字符串类型的名字, 返回值是True或者False

    class People:
         def run(self):
             print('running..')
    
    print( hasattr(People() , 'run') )
    print( hasattr(People , 'run') )

      getattr(), 获取对象或者类的参数, 第一个参数是类或者对象, 第二个参数是字符串类型的名字,但是使用对象和类室友区别的

      另外还可以设置第三个参数, 当该属性不存在的时候返回那个值

    whc = People()
    func = getattr(whc, 'run')
    func()
    func = getattr(People, 'run')
    func(whc)
    print( getattr(whc, 'running', '该属性不存在') )
    

      setattr(), 设置属性, 同样可以给对象和类绑定

    whc = People()
    setattr(whc, 'name', 'weihuchao')
    setattr(People, 'country', 'China')
    print(whc.__dict__)
    print(People.__dict__)
    

      delattr(), 删除属性

    delattr(whc, 'name')
    delattr(People,'country')
    print(whc.__dict__)
    print(People.__dict__)
    

      使用反射的好处, 可插拔机制

        因为可以查看类中是否含有某属性, 在不同模块写程序的时候, 只需要判断该属性有没有就可使程序健壮的完成, 而不必要等待相关联的模块完成

    2.2 反射模块

      在正常使用的导入模块是使用import或者from, 但是要反射某个模块, 同样是根据输入的字符串的来反射  

      具体的反射有两种操作, 一个是内置函数__import__(), 另一个是使用模块importlib

      具体模式如下

    返回值 = __import__(模块名字字符串)
    #或者
    import importlib
    返回值 = importlib.import_module(模块名字字符串)

      返回值就是相当于反射回来的命名空间的名字

      一般建议使用第二种方法

    name = 'time'
    nameSpace = __import__(name)
    print(nameSpace.time())
    #或者
    import importlib
    name = 'time'
    nameSpace = importlib.import_module(name)
    print(nameSpace.time())

      另外反射的例子

    3 __getattr__等

      在类中, 还可以定义__getattr__(), __setattr__() 和 __deltattr__()

      定义了__setattr__() 和 __deltattr__()函数之后, 类中所有的设置, 删除属性和方法的时候都会调用它

        具体来说, 由于设置了这两个函数, 所以在完成设置和删除功能的时候, 不能再使用赋值语句和setattr()这个内置函数的处理了

        要处理结果需要使用__dict__属性来完成

        __setattr__() 默认有三个参数, 一个是self, 第二个是键, 第三个是值

        __deltattr__()认有两个个参数,一个self, 另一个是需要删除的属性的名字

      但是__getattr__()函数特殊, 它是在调用attr不存在的时候才调用, 基于这个特性有很强的使用效果

      具体的实例如下

    class Foo:
        x=1
        def __init__(self,y):
            self.y=y
        def __getattr__(self, item):
            print('----> from getattr:你找的属性不存在')
        def __setattr__(self, key, value):
            print('----> from setattr')
            # self.key=value #这就无限递归了,
            # self.__dict__[key]=value #应该使用它
        def __delattr__(self, item):
            print('----> from delattr')
            # del self.item #无限递归了
            self.__dict__.pop(item)
    
    #__setattr__添加/修改属性会触发它的执行
    f1=Foo(10)
    print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
    f1.z=3
    print(f1.__dict__)
    
    #__delattr__删除属性的时候会触发
    f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
    del f1.a
    print(f1.__dict__)
    
    #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
    f1.xxxxxx
    

    4 授权

      授权是__getattr__()函数的应用

      具体实例是实现一个记录日志的Open类

      在__init__()函数中, 可以通过传入的内容来获得文件句柄, 再编写一个write()函数, 通过文件句柄写入日志信息即可

      但是除了wirte()函数功能之外别的文件函数像close()和flush()等都不需要修改的, 但是总不能每一个都写一遍

      所以利用__getattr__()不存在属性调用的特性, 利用__getattr__()有两个参数一个是self另一个就是获取的属性名这个特性, 通过内置函数getattr()来具体取得那些相关属性 

      具体代码如下

    import time
    class LogFile:
        def __init__(self,filename,mode='r',encoding='utf-8'):
            self.file=open(filename,mode,encoding=encoding)
        def write(self,line):
            t=time.strftime('%Y-%m-%d %T')
            self.file.write('%s %s' %(t,line))
            
        def __getattr__(self, item):
            print("aaa")
            return getattr(self.file,item)
    
    f1=LogFile('log', 'w+')
    f1.write('create logs..')
    f1.seek(0)
    print(f1.read())
    f1.close()
    

    5 包装

      通过继承基本类型list, 来获得list的全部功能, 通过重写append()方法, 来加入对添加进来的值进行类型判断, 从而实现自定义功能

      具体代码如下

    class List(list):
        def append(self, p_object):
            if not isinstance(p_object,int):
                raise TypeError('插入的值必须是int类型的!')
            super().append(p_object)
    
    myList = List([1,2,3,4])
    print(myList)
    myList.append(5)
    print(myList)
    try:
        myList.append('test')
    except:
        print("输入值类型不正确")
    print(myList)
    

      

    人若有恒 无所不成
  • 相关阅读:
    CSS简单的四种引入方式
    html之表单标签
    html基础标签之head和body标签
    Python之协程的实现
    Python之实现不同版本线程池
    Python多进程之multiprocessing模块和进程池的实现
    Python之queue模块
    sqlserver 时间格式化
    关于sql server 代理(已禁用代理xp)解决办法
    sqlserver如何启动数据库邮件
  • 原文地址:https://www.cnblogs.com/weihuchao/p/6757345.html
Copyright © 2020-2023  润新知