• 反射、定制数据类型


    isinstance,issubclass
    isinstance(obj,cls) ,检查obj是否是类cls的对象
     
    class Foo(object):
        pass
    
    obj = Foo()
    print(isinstance(obj,Foo))

    issubclass(sub,super)检查sub类是否是super类的派生类
    class Foo:
        pass
    class sub(Foo):
        pass
    
    print(issubclass(sub,Foo))

    反射:getattr,setattr,delattr,hasattr
    hasattr:查看对象中是否有此字符串属性,返回Ture或False
    class Foo:
        def __init__(self,name):
            self.name = name
    
    f = Foo('Mitsui')
    print(hasattr(f,'name'))

    getattr:查看对象是否有此属性,返回属性的值。
    class Foo:
        country = 'China'
        def __init__(self,name):
            self.name = name
    
    f = Foo('Mitsui')
    res = getattr(f,'name')
    res1 = getattr(f,'country')
    print(res1,res)


    setattr:setattr(obj,str,value)设置对象的属性
    setattr(f,'age',18)
    print(f.__dict__)
    print(f.age)

    delattr:delattr(obj,str)删除对象的属性
    delattr(f,'name')
    print(f.__dict__)
    print(f.name)
    >>>:
    {'age': 18} print(f.name) AttributeError: 'Foo' object has no attribute 'name'
    
    

    一切皆对象,类也是对象,也可以调用以上的方法。
    当前位置导入由当前文件转换的模块:
    import sys
    this_module = sys.modules[__name__]

    基于这些反射方法,可以实现代码可插拔机制:
    在代码合作编写阶段,一方不需等另一方的编写完成,只需了解他所具备的属性功能便可自行编写自己的代码,
    这样可以确保自己不受他人的影响。比如下面这一段代码:
    Client端:
    class FtpClient:
        'ftp客户端,但是还没有实现具体的功能'
        def __init__(self,addr):
            print('正在连接服务器[%s]'% addr)
            self.addr = addr
    
    Server端:
    from FtpClient import FtpClient
    f1 = FtpClient('192.168.1.1')
    if hasattr(f1,'get'):
        func_get = getattr(f1,'get')
        func_get()
    else:
        print('----->还未存在此方法')
        print('先处理其它逻辑')
    执行结果:
    >>>>:
    正在连接服务器[192.168.1.1]
    ----->还未存在此方法
    先处理其它逻辑
    View Code
    当client端get方法还未编写,不影响server端代码的运行,而当Client端编写好get方法
    此时运行Server端会根据代码做出相应的变动
    class FtpClient:
        'ftp客户端,但是还没有实现具体的功能'
        def __init__(self,addr):
            print('正在连接服务器[%s]'% addr)
            self.addr = addr
        def get(self):
            print('get正在运行')
    
    >>>>:
    正在连接服务器[192.168.1.1]
    get正在运行
    View Code

    通过字符串导入模块:
    m = input('输入你要导入的模块')
    m1 = __import__(m)(不建议)   == m1 = importtlib.import_module(m)(官方建议方法)

    内置attr:__getattr__,__setattr__,__delattr__
    __getattr__:当对象执行不存在的属性时,会触发__getattr__
    class Foo:
        def __init__(self,name):
            self.name = name
        def __getattr__(self, item):
            print('__getattr__已触发')
    
    f1 = Foo('Mitsui')
    print(f1.name)
    print(f1.names)
    >>>>:
    Mitsui
    __getattr__已触发
    None            #有返回值默认是None
    View Code
    __setattr__:为一个对象的属性赋值时,将触发此方法,可以由此限定参数类型:
    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.__dict__[key] = value
    
    f1 = Foo('Mitsui')
    print(f1.name)
    f1.name = 'BOBO'
    print(f1.name)
    
    #当f1.name = 123执行时会触发抛出的异常TypeError,f1.name = 'BOBO'则会正常运行。
    View Code
    __delattr__:采用del删除属性时触发,一样可以限制删除功能主动抛出异常。

    定制自己的数据类型:
    1.继承的方式
    继承list的方法:
    class List(list):
        def append(self, p_object):
            if not isinstance(p_object,int):
                #派生自己的append:加上类型检查
                raise TypeError('must be int')
            super().append(p_object)
    
        def insert(self, index, p_object):
            if not isinstance(p_object,int):
                raise TypeError('must be int')
            super().insert(index,p_object)
    
        @property
        def mid(self):
            '也可以新增自己的属性'
            index = len(self) // 2
            return self[index]
        #如果没有派生跟新增属性,其余的方法都会继承list方法
    l = List([1,2,3])
    print(l)
    l.append(5)
    l.insert(1,'234')
    print(l)
    View Code
    2.授权的方式
    授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。
    其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
    #定制一个具有日志功能的文件操作类方法:
    import time
    
    class Open:
        def __init__(self,filepath,m='r',encode='utf-8'):  #传入打开文件所需的参数
            self.x=open(filepath,mode=m,encoding=encode)   #拿到文件的句柄self.x
            self.filepath=filepath
            self.mode=m
            self.encoding=encode
    
        def write(self,line):           #定制自己的文件写功能
            print('f自己的write',line)
            t=time.strftime('%Y-%m-%d %X')          #得到一个格式输出的时间 年Y月m日d 时分秒X
            self.x.write('%s %s' %(t,line))       #根据句柄引用文件原本功能‘write’写入文件的内容,包含当前时间以及传入的值
    
        #write功能实现了,文件操作还有其它诸如seek、read等功能,而这些功能开发时可能不需要定制,open又不能继承,该怎么解决呢
        #把每个功能重写一遍?那样效率太低太繁琐了,这时候我们便可以用到__getattr__ 当使用者在调用read等方法时,Open类自然找
        #不到这个功能,找不到的时候会执行什么呢?没错就是__getattr__ 方法,此时编写一个__gettattr__方法,调用原本属于文件
        #操作的功能,问题也就迎刃而解了。
    
        def __getattr__(self, item):
            # print('=------>',item,type(item))
            return getattr(self.x,item)  #self.x等于文件句柄 用getattr方法,拿到句柄里面的item方法。即
            #getattr(self.x,item)当输入的参数item=read 则相当于拿到了文件初始的read方法,加括号即可运行
    
    f = Open('a.txt','w+')
    f.write('11111111111111')
    f.seek(0)
    print(f.read())
    
    >>>:
    f自己的write 11111111111111
    2017-04-24 17:26:01 11111111111111
    View Code

    思考:

       基于授权定制自己的列表类型,要求定制的自己的__init__方法,
    定制自己的append:只能向列表加入字符串类型的值
    定制显示列表中间那个值的属性(提示:property)
    其余方法都使用list默认的(提示:__getattr__加反射)

     1 class List:
     2     def __init__(self,v):
     3         self.x = v
     4     def __str__(self):
     5         return str(self.x)
     6     def append(self,value):
     7         if not isinstance(value,str):
     8             raise TypeError('must be str')
     9         self.x.append(value)
    10     @property
    11     def mid(self):
    12         return self.x[(len(self.x)//2)]
    13 
    14     def __getattr__(self, item):
    15         return getattr(self.x,item)
    View Code
     
    
    
    
     
  • 相关阅读:
    springboot项目引入通用mapper(tk.mybatis.mapper)的时候一些可能会踩的坑
    Zookeeper和Dubbo基本配置和调用
    Zookeeper和Dubbo介绍
    Git的基础命令大全,拉取推送,分支,合并,冲突
    Maven内置tomcat
    Maven高级,依赖传递和解决冲突,版本锁定,提取统一版本号
    SpringMvc的自定义异常,交给SpringMvc管理
    IDEA创建MavenWeb项目慢,问题根除
    Docker安装指南
    Docker容器入门
  • 原文地址:https://www.cnblogs.com/mitsui/p/6757433.html
Copyright © 2020-2023  润新知