【反射机制】
1.定义
python中的反射就是通过字符串的形式操作对象相关的属性,python中一切事物都是对象,都可以用到反射
反射机制指的是在程序的运行状态中, 对于任意一个类,都可以知道这个类的所有属性和方法;对于任意一个对象,都能够调用他的任意方法和属性。 这种动态获取程序信息以及动态调用对象的功能称为反射机制。
hasattr 检测是否含有某属性
getattr 获取属性
setattr 设置属性,没有返回值
delattr 删除属性
好处:反射可以提前定义好接口、接基于类的视图
2.如何实现反射
class People: def __init__(self, name, age): self.name = name self.age = age def say(self): print('<%s:%s>' % (self.name, self.age)) obj = People('jh', 26) # 实现反射机制的步骤 # 1.先通过dir:查看出某一个对象下可以.出来哪些属性 print(dir(obj)) # 2.可以通过字符串反射到真正的属性上,得到属性值 print(obj.__dict__['name']) # 或是: print(obj.__dict__[dir(obj)[-3]]) # 两者都有局限性(1.不是所有类型都有__dict__属性 2.dir()返回的是列表,需要取值,但是我们不确定对应的索引是不是我们想去的那个值) ======================================== # 四个内置函数的使用(通过字符串来操作属性值) print(hasattr(obj, 'name')) # 判断是否有name属性,有返回True,没有返回False print(getattr(obj, 'name')) # 获取属性 print(setattr(obj, 'name', 'JH')) #设置值,没有返回值,返回None print(obj.name) # JH delattr(obj, 'name') # 删除属性操作 print(obj.__dict__) # __dict__验证:删除了name,只留下年龄:{'age': 26}
3.案例
【元类】
元类:创建类的类就叫元类(metaclass)函数type其实就是一个元类,type 就是Python在背后用来创建所有类的元类。(一切皆对象)
关系:元类-----实例化-----》类(People)-----实例化-----》对象(obj)
1.class关键字创造类People的步骤
# 类有三大特征: # 1.类名 class_name = "People" # 2.类的基类(元组) class_bases = (object,) # 3.执行类体代码拿到类的名称空间{} class_dic = {} class_body = """ def __init__(self, name, age): self.name = name self.age = age def say(self): print('<%s:%s>' % (self.name, self.age)) """
==========================================
exec(class_body, {}, class_dic) # 产生的名字都放到{}里面,自己造
2.====如何自定义元类来控制类的产生=======
1 class Mymeta(type): # 只有继承了type类的类才是元类 2 # 空对象,’People‘,(),{...} 3 def __init__(self, x, y, z): 4 print('run') 5 print(y) 6 print(self.__bases__) 7 if not x.istitle(): 8 raise NameError('类名的首字母必须大写') 9 10 # 当前所在的类,*调用类时所传入的参数 11 def __new__(cls, *args, **kwargs): # 先造空对象,早于init产生 12 # 造Mymeta的对象 13 print('run1111') 14 # return super().__new__(cls, *args, **kwargs),问父类要 15 return type.__new__(cls, *args, **kwargs) # 指名道姓的要 16 17 18 # 调用Mymeta发生的三件事: 19 # 1.先造一个空对象=》people,调用类内的__new__方法 20 # 2.调用Mymeta这个类内的__init__方法,完成初始化对象的操作 21 # 3.返回初始化好的对象 22 # class People(metaclass=Mymeta): 23 24 # Pepole=Mymeta('Pepole',(object),{....}) 25 # 调用Mymeta发生的三件事:调用Mymeta就是type.__call__ 26 # 1.先造一个空对象=》people,调用Mymeta类内的__new__方法 27 # 2.调用Mymeta这个类内的__init__方法,完成初始化对象的操作 28 # 3.返回初始化好的对象 29 class People(metaclass=Mymeta): 30 def __init__(self, name, age): 31 self.name = name 32 self.age = age 33 34 def say(self): 35 print('<%s:%s>' % (self.name, self.age)) 36 37 38 people = People('jh', 26) 39 people.say() 40 41 # =====================强调 42 # 只要是调用类,那么会一次调用 43 # 1.类内的__new__ 44 # 2.类内的__init__ 45 46 47 print('============__call__====================') 48 49 50 class Foo: 51 def __init__(self, x, y): 52 self.x = x 53 self.y = y 54 55 def __call__(self, *args, **kwargs): 56 print('==?>', args, kwargs) 57 return 123 58 59 60 obj = Foo(111, 222) 61 # print(obj) # obj.__str__ 62 63 # 判断obj能否调用这个条件(不能) 64 res = obj(1, 2, 3, a=4, b=5) # 先找类内的__call__方法,如果有,就调用,如果没有,就报错 65 print(res) 66 67 68 # 应用:如果想让一个对象可以加()调用,需要在该对象的类中添加一个方法:__call__ 69 # ===========总结 70 # 对象()-------->类中的__call__方法 71 # 类()-------->自定义元类内的__call__方法 72 # 自定义元类()-------->内置元类__call__方法 73 74 # 自定义元类控制类的调用=====》类的对象的产生 75 class Mymeta(type): 76 def __call__(self, *args, **kwargs): 77 # 1.Mymeta.__call__函数内会先调用People内的__new__ 78 people_obj = self.__new__(self) 79 # 2.Mymeta.__call__函数内会调用People内的__init__ 80 self.__init__(people_obj, *args, **kwargs) 81 # 3.Mymeta.__call__函数内会返回初始化好的对象(People()) 82 return people_obj 83 84 85 # 类的产生 86 # People=Mymeta()====》type.__call__====>干了三件事: 87 # 1.type.__call__函数内会先调用Mymeta内的__new__ 88 # 2.type.__call__函数内会调用Mymeta内的__init__ 89 # 3.type.__call__函数内会返回初始化好的对象(Mymeta()) 90 class People(metaclass=Mymeta): 91 def __init__(self, name, age): 92 self.name = name 93 self.age = age 94 95 def say(self): 96 print('<%s:%s>' % (self.name, self.age)) 97 98 def __new__(cls, *args, **kwargs): 99 # 产生真正的对象 100 return object.__new__(cls) 101 102 103 # 类的调用 104 # obj = People('jh', 26)===>Mymeta.__call__====>干了三件事: 105 # 1.Mymeta.__call__函数内会先调用People内的__new__ 106 # 2.Mymeta.__call__函数内会调用People内的__init__ 107 # 3.Mymeta.__call__函数内会返回初始化好的对象(People()) 108 obj = People('jh', 26) 109 print(obj) # 123123123 110 111 print(obj.__dict__) 112 # {'name': 'jh', 'age': 26} 113 114 115 # 属性查找的顺序:对象===》类===》父类(父类不是元类) 116 # 执行顺序 117 # 对象的类中的.__call__ 118 # 对象.__new__ 119 # 对象.__init__
。
。
。
【魔法方法】
1 魔法方法:__call__,__init__,__new__,__str__... 2 类加()触发类的元类的__call__方法 3 __str__ 打印时触发 str函数或者print函数—>obj.str() 4 __init__ 是初始化方法,通过类创建对象时,自动触发执行 5 __new__ 是创建对象时为对象分配空间、在初始化init之前被调用 6 当我们创建实例的时候、 __new__方法在__init__方法之前被调用并将__new__方法的返回值将传递给__init__方法作 7 为第一个参数,最后__init__给这个实例设置一些参数。