• 面向对象-反射和__getattr__系列


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

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

    class Foo:
        pass
       
    obj = Foo()
    isinstance(obj, Foo)
    

    issubclass(sub, super)检查sub类是否是 super 类的派生类

    class Foo:
        pass
    
    class Bar(Foo):
        pass
    
    issubclass(Bar,Foo)
    

    反射

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

    # 反射
    class People:
        country = "china"
        def __init__(self,name):
            self.name = name
    
        def walk(self):
            print("%s is walking" % self.name)
    
    p = People("egon")
    print(p.__dict__)           #     {'name': 'egon'}
    print(People.__dict__)       # {'__weakref__': <attribute>,...... '__module__':  'country': 'china'}
    
    # hasattr检测是否含有某属性
    print(hasattr(p, "name"))          # True
    print(hasattr(p, "country"))       # True
    print(hasattr(p, "walk"))          # True
    print(hasattr(People, "name"))     # False
    print(hasattr(People, "country"))  # True
    print(hasattr(People, "walk"))     # True
    
    
    # getattr(obj,name)获取属性
    n1 = getattr(p,"country")  # china
    n2 = getattr(p,"name")     # egon
    n3 = getattr(p,"walk")     # bound method
    n4 = getattr(People,"country") # china
    n5= getattr(People,"name")  # AttributeError,没这个属性
    n6= getattr(People,"walk")    # function method
    
    
    # setattr(x, y, v)设置属性
    setattr(p, "age", 18)
    setattr(p, "func", lambda self:self.name + "_pirate")
    print(type(p.func))  # <class 'function'>,setattr设置的是类属性,不是绑定对象的方法
    print(p.func(p))     # egon_pirate
    print(p.age)         # 18
    
    
    # delattr(x, y) 删除属性
    delattr(p, "name")
    delattr(p, "walk") # AttributeError,不能删除绑定方法
    delattr(People, "walk")
    delattr(p,"fa")      # 没有属性也报错
    

    反射当前模块的属性

    ##反射当前模块的属性
    import sys
    x = 1111
    class Foo:
        pass
    def s1():
        print("from function s1")
    
    def s2():
        print("S2")
    
    this_module = sys.modules[__name__]  # 拿到当前模块的属性
    
    print(this_module)                # <module '__main__' from 'C:/workspace/test.py'>
    print(hasattr(this_module,"s1"))  # True
    print(hasattr(this_module,"s2"))  # True
    print(hasattr(this_module,"s3"))  # False
    print(hasattr(this_module, "Foo")) # True
    f = getattr(this_module,"s1")    
    f()    # from function s1
    

    反射当前模块属性应用之增删改查

    # 应用之增删改查
    def add():
        print("---add function---")
    
    
    def delete():
        print("---delete function---")
    
    
    def modify():
        print("---modify function---")
    
    
    def search():
        print("---search function---")
    
    
    import sys
    this_module = sys.modules[__name__]
    # print(this_module.__dict__)      # 'search': <function search at 0x017A5228>...
    while True:
        cmd = input(">>:").strip()
        if hasattr(this_module, cmd):      # 判断当前模块是否有这个属性
            f = getattr(this_module, cmd)  # 得到该属性
            f()   # 运行函数
        else:
            print("没有该功能请继续输入")
    

    反射实现可插拔机制
    事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能

    # FtpClient.py文件
    class FtpClient:
        ' ftp客户端,但是还么有实现具体的功能 '
        def __init__(self,addr):
            print('正在连接服务器[%s]' %addr)
            self.addr=addr
    
    
        # def download(self):
        #     print("download...")
    
    # FtpServer文件
    from FtpClient import FtpClient
    data = FtpClient("192.168.1.123")
    if hasattr(data, "download"):
        func = getattr(data, "download")
        func()   # FtpClient存在该属性,则拿到执行,不存在执行else
    else:
        print("不存在此方法")
        print("处理其他逻辑")
    

    通过字符串导入模块

    # 通过字符串导入模块
    # 推荐使用
    import importlib
    t = importlib.import_module("time")
    print(t.strftime("%Y-%m-%d %X")) # 2017-04-24 15:53:42
    
    # 不推荐
    t = __import__("time")
    print(t.strftime("%Y-%m-%d %X"))  # 2017-04-24 15:54:26
    

    __setattr__,__delattr__,__getattr__

    #**__setattr__,__delattr__,__getattr__基本用法**
    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __getattr__(self, item):   # 属性不存在才触发
            print("getattr--->%s %s" % (item, type(item)))
    
        def __setattr__(self, key, value):
            if not isinstance(value,str):  # 限制了所有设置属性必须为str,和@property不同
                raise TypeError("must be str")
            print("----------setter")
            self.__dict__[key] = value
    
        def __delattr__(self, item):   # __delattr__删除属性的时候会触发
            print("-------------deltter")
            self.__dict__.pop(item)
    
    
    f = Foo("egon")
    # __getattr__只有在使用点调用属性且属性不存在的时候才会触发
    print(f.name)   # egon, 正常执行
    print(f.fjkad)  # getattr--->fjkad <class 'str'>,找不到触发__getattr__
    
    
    # __setattr__添加/修改属性会触发它的执行
    f.nickname = "邹润成"
    print(f.__dict__)  # {'name': 'egon', 'nickname': '邹润成'}
    f.__dict__['a']=3  # 可以直接修改属性字典,来完成添加/修改属性的操作
    
    
    # __delattr__删除属性的时候会触发
    del f.nickname
    print(f.__dict__)  # {'name': 'egon'}
    

    定制自己的数据类型

    python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识
    使用继承定制自己的数据类型

    # 基于继承标准类型定制自己的数据类型
    class List(list):
        def append(self, p_object):
            if not isinstance(p_object, int): # 为append方法,进行类型限制 
                raise TypeError("must be int")
            super().append(p_object)
    
    
        @property
        def mid(self):
            "新增加的属性,取中间值"
            index = len(self)//2
            return self[index]
    
    
    a = List([1, 2, 3])
    a.append(4)
    a.append(5)
    # a.append("5") # TypeError: must be int
    print(a)      # [1, 2, 3, 4, 5]
    print(a.mid)  # 3
    

    使用授权的方法定制数据类型

    # 作业:
    # 	基于授权定制自己的列表类型,要求定制的自己的__init__方法,
    # 	定制自己的append:只能向列表加入字符串类型的值
    # 	定制显示列表中间那个值的属性(提示:property)
    # 	其余方法都使用list默认的(提示:__getattr__加反射)
    class LIST:
        def __str__(self):
            return str(self.seq)
        def __init__(self,*args):
            self.seq = list(*args)
    
    
        def append(self, value):
            if not isinstance(value, str):
                raise TypeError("必须传字符串")
            self.seq.append(value)
    
        @property
        def mid(self):
            index = len(self.seq)//2
            return self.seq[index]
    
    
        def __getattr__(self, item):
            return getattr(self.seq, item)
    
    
    l = LIST(["1","2","3"])
    l.append("4")
    l.append("5")
    print(l)        # ['1', '2', '3', '4', '5']
    print(l.mid)    # 3
    print(l.pop())  # 5
    print(l)        # ['1', '2', '3', '4']
    

    使用授权的方法模拟日志

    # 不使用继承模拟日志
    import time
    class Open:
        def __init__(self,filepath,mode="r",encoding="utf8"):
            self.x = open(filepath, mode=mode, encoding=encoding)
            self.filepath = filepath
            self.modde = mode
            self.encoding = encoding
    
        def write(self, line):
            print("from f ", line)
            t = time.strftime("%Y-%m-%d %X")
            self.x.write("%s %s
    " % (t, line))
    
    
    f = Open("a.txt", "w", "utf8")
    f.write("111111111")
    f.write("222222222")
    f.write("333333333")
    

    增强版

    # 加强版
    import time
    class Open:
        def __init__(self,filepath,mode="r", encoding="utf8"):
            self.x = open(filepath, mode=mode, encoding=encoding)
            self.filepath = filepath
            self.mode = mode
            self.encoding = encoding
    
        def write(self, line):
            print("from f ", line)
            t = time.strftime("%Y-%m-%d %X")
            self.x.write("%s %s
    " % (t, line))
    
    
        def __getattr__(self, item):
            return getattr(self.x, item)
    
    
    f = Open("a.txt")
    a = f.read()
    print(a)
    # 2017-04-24 17:15:36 111111111
    # 2017-04-24 17:15:36 222222222
    # 2017-04-24 17:15:36 333333333
    
  • 相关阅读:
    zip
    yield
    日记
    cat
    genfromtext
    pytorch易忘
    小程序入门(一)
    (二)连接数据库使用Model对象对数据库进行操作(CRUD)
    (一)Moogose(node.js对数据库进行操作)
    CURD练习
  • 原文地址:https://www.cnblogs.com/zouruncheng/p/6758123.html
Copyright © 2020-2023  润新知