• day28


    isinstance与issubclass

    isinstance

    在游戏项目中,我们会在每个接口验证客户端传过来的参数类型,如果验证不通过,返回给客户端“参数错误”错误码。

    这样做不但便于调试,而且增加健壮性。因为客户端是可以作弊的,不要轻易相信客户端传过来的参数。

    验证类型用type函数,非常好用,比如

    print(type('foo') == str)
    True
    print(type(2.3) in (int, float))
    True
    

    既然有了type()来判断类型,为什么还有isinstance()呢?

    一个明显的区别是在判断子类。

    type()不会认为子类是一种父类类型;isinstance()会认为子类是一种父类类型。

    千言不如一码。

    class Foo(object):
        pass
     
    class Bar(Foo):
        pass
     
    print(type(Foo()) == Foo)
    True
    print(type(Bar()) == Foo)
    False
    # isinstance参数为对象和类
    print(isinstance(Bar(),Foo))
    True
    

    需要注意的是,旧式类跟新式类的type()结果是不一样的。旧式类都是<type 'instance'>。

    # python2.+
    class A:
        pass
     
    class B:
        pass
     
    class C(object):
        pass
    
    print('old style class',type(A()))  # old style class <type 'instance'>
    
    print('old style class',type(B()))  # old style class <type 'instance'>
    
    print('new style class',type(C()))  # new style class <class '__main__.C'>
    
    print(type(A()) == type(B()))  # True
    

    注意:不存在说isinstance比type更好。只有哪个更适合需求。

    issubclass

    class Parent:
        pass
    
    
    class Sub(Parent):
        pass
    
    
    print(issubclass(Sub, Parent))
    True
    print(issubclass(Parent, object))
    True
    

    反射

    定义

    反射就是通过字符串来操作类或者对象的属性

    • 反射本质就是在使用内置函数,其中反射有以下四个内置函数:

      1. hasattr:判断一个方法是否存在与这个类中
      2. getattr:根据字符串去获取obj对象里的对应的方法的内存地址,加"()"括号即可执行
      3. setattr:通过setattr将外部的一个函数绑定到实例中
      4. delattr:删除一个实例或者类中的方法
      

    栗子:

    class Foo:
        def __init__(self,name,sex):
            self.name=name
            self.sex=sex
        def tucao(self,name):
            return f'{name}疯狂吐槽'
        def bianxing(self,sex):
            self.sex=sex
    f=Foo('nick','nan')
    if hasattr(f,'tucao'):
        f.bianxing('nv')
        res=getattr(f,'tucao')(f.name)
        print(res)
        print(getattr(f,'sex'))
    else:
        print('your mother boom')
    
    def gaoji(name):
        print(f'{name}疯狂搞基')
    
    setattr(f,'age',18)
    print(getattr(f,'age'))
    setattr(f,'gaojia',gaoji)
    getattr(f,'gaojia')(f.name)
    
    delattr(f,'sex')
    print(getattr(f,'sex'))
    

    nick疯狂吐槽
    nv
    18
    nick疯狂搞基
    最后会报错,因为sex属性被删除

    反射在模块中的应用

    # test.py
    def f1():
        print('f1')
    
    
    def f2():
        print('f2')
    
    
    def f3():
        print('f3')
    
    
    def f4():
        print('f4')
    
    
    a = 1
    import test as ss
    
    ss.f1()
    ss.f2()
    print(ss.a)
    

    我们要导入另外一个模块,可以使用import.现在有这样的需求,我动态输入一个模块名,可以随时访问到导入模块中的方法或者变量,怎么做呢?

    imp = input(“请输入你想导入的模块名:”)
    CC = __import__(imp) 這种方式就是通过输入字符串导入你所想导入的模块 
    CC.f1()  # 执行模块中的f1方法
    

    上面我们实现了动态输入模块名,从而使我们能够输入模块名并且执行里面的函数。但是上面有一个缺点,那就是执行的函数被固定了。那么,我们能不能改进一下,动态输入函数名,并且来执行呢?

    # dynamic.py
    imp = input("请输入模块:")
    dd = __import__(imp)
    # 等价于import imp
    inp_func = input("请输入要执行的函数:")
    
    f = getattr(dd, inp_func,
                None)  # 作用:从导入模块中找到你需要调用的函数inp_func,然后返回一个该函数的引用.没有找到就烦会None
    
    f()  # 执行该函数
    请输入模块:time
    请输入要执行的函数:time
    
    
    
    
    
    1560959528.6127071
    

    上面我们就实现了,动态导入一个模块,并且动态输入函数名然后执行相应功能。

    当然,上面还存在一点点小问题:那就是我的模块名有可能不是在本级目录中存放着。有可能是如下图存放方式:

    |- day24
        |- lib
            |- common.py
    

    那么这种方式我们该如何搞定呢?看下面代码:

    dd = __import__("lib.text.commons")  # 这样仅仅导入了lib模块
    dd = __import__("lib.text.commons", fromlist=True)  # 改用这种方式就能导入成功
    # 等价于import config
    inp_func = input("请输入要执行的函数:")
    f = getattr(dd, inp_func)
    f()
    

    内置方法

    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)
    
    
    f1 = Foo(10)
    

    一、setattr

    • 添加/修改属性会触发它的执行
    print(f1.__dict__
          )  # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
    f1.z = 3
    print(f1.__dict__)
    

    二、delattr

    • 删除属性的时候会触发
    f1.__dict__['a'] = 3  # 我们可以直接修改属性字典,来完成添加/修改属性的操作
    del f1.a
    print(f1.__dict__)
    ----> from delattr
    {}
    

    三、 getattr

    • 只有在使用点调用属性且属性不存在的时候才会触发
    f1.xxxxxx
    ----> from getattr:你找的属性不存在
    
  • 相关阅读:
    printf里的=、++
    线程也疯狂-----异步编程
    自己搭建node服务器环境(请求静态资源、get请求、post请求)
    React学习
    2020.10-2021-01总结
    接圈的作用和缺点
    CWnd,HWND; CDC,HDC
    Python通过requests模块处理form-data请求格式
    element-ui resetFields 无效的问题
    用python 将数字每三组分割
  • 原文地址:https://www.cnblogs.com/leaf-wind/p/11449422.html
Copyright © 2020-2023  润新知