【反射机制】

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__给这个实例设置一些参数。

 

posted on 2024-01-05 20:57  认真的六六  阅读(4)  评论(0编辑  收藏  举报