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:你找的属性不存在

原文地址:https://www.cnblogs.com/bjlxxbj/p/11508208.html