反射与元类
反射与元类
反射实战案例
1.案例1
import settings # 调用我们呢刚刚配置的文件
new_dic = {} # 制造一个空字典
print(dir(settings)) # 将settings内部的所有可以使用句点符点出来的功能都给他展示出来
# ['AGE', 'HOBBY', 'NAME', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
for i in dir(settings):
if i.isupper(): # 判断是否为纯大写,如果是纯大写的话那么就获取该大写名字所对应的值
value = getattr(settings, i) # 获得对所对应的属性
new_dic[i] = value # 生成一个字典属性将大写字母的值当作字典的k,然后属性当作v值并纯给之前定义的字典
print(new_dic) # 打印字典
2.模拟cmd终端命令
class windows():
def dir(self):
print('dir获取当前目录下所有文件名称')
def ls(self):
print('ls获取当前路径下所有文件名称')
def ipconfig(self):
print('ipconfig获取当前计算机的网卡信息')
obj = windows()
while True:
cmd = input('请输入您的指令')
if hasattr(obj, cmd):
cmd_name = getattr(obj,cmd)
cmd_name()
else:
print(f'{cmd} 不是内部命令或外部命令,也不是可运行的程序或批处理文件')
常见魔法方法
1.常见魔法
class MyClass(object):
def __init__(self, name): # __init__() 用于初始化实例,所以该方法是在实例对象创建后被调用,它是实例级别的方法,用于设置对象属性的一些初始值
print('from__init__')
pass
self.name = name
def __str__(self): # print([对象]) 是个字符串的时候触发 __str__ 的执行
print('from__str__')
return f"对象名称:{self.name}"
def __call__(self, *args, **kwargs): # [对象] + ( ) 就触发 __call__ 的执行
print(args)
print(kwargs)
print('from __call__')
def __getattr__(self, item): # 在 [对象].[属性] 获取属性不存在的时候会触发它的执行
print('from __getattr', item)
return f'您想要获得的属性值:{item}不存在'
def __setattr__(self, key, value): # 在 [对象].[属性] = [值] 设置属性值的时候就会触发它的执行
print(key)
print(value)
print('from __setattr')
super.__setattr__(self, key, value)
def __del__(self): # 在 del [对象].[属性] 删除属性的时候会触发它的执行
print('from __del__')
pass
def __getattribute__(self, item): # 先执行 __getattribute__—>去类的名称空间找—>__getattr__(本质是去对象自己的名称空间找)
print('from __getattribute__')
return super(MyClass, self).__getattribute__(item)
def __enter__(self): # 上下文管理协议就是 with 语句, 为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__()和__exit__()方法
print('from __enter__')
def __exit__(self, exc_type, exc_val, exc_tb): # 如果__exit__()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行
print('from __exit__')
obj = MyClass('joseph')
obj1 = MyClass('jason')
print(obj.name) # 获取对象拥有的属性名name
print(obj.age) # 获取对象不存在的属性名age
print(obj.pwd) # 获取对象不存在的属性名pwd
print(obj.__dict__)
print(obj.name)
# del obj
print(obj.name)
with obj as f:
print(f)
with open() as f:
pass
常见魔法方法笔试题
class Context:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def do_something(self):
pass
with Context() as f:
f.do_something()
元类简介
元类是什么?
所有的对象都是实例化或者说是通过调用类而得到的,python中一切皆对象,通过class关键字定义的类本质也是对象,对象又是通过调用类得到的,因此通过class关键字定义的类肯定也是调用了一个类得到的,这个类就是元类。
怎样辨别元类
由于在python3中没有经典类和新式类的区别,因此python3中object是所有类的基类,那内置元类type又是什么?type是object类的类型,总结来说就是type是object的类型,同时,object又是type的基类,在python3中类和类型是同一种东西,因此对象.__class__和type(对象)得到的结果是一致的,object的基类为空,但是type的基类为object,但是object的类型又是type。
类型
object.__class__
<class 'type'>
type.__class__
<class 'type'>
object.__bases__()
type.__bases__
<class 'object'>
type(object)
<class 'type'>
type(type)
<class 'typ'>
产生类的两种方式
1.class关键字
class MyClass:
pass
2.利用元类type
type(类名,类的父类,类的名称空间)
"""
学习元类其实就是掌握了类的产生过程 我们就可以在类的产生过程中高度定制化类的行为
eg:
类名必须首字母大写
上述需求就需要使用元类来控制类的产生过程 在过程中校验
"""
元类的基本使用
1.只有继承了 type 的类才可以被称为元类
class MyMetaClass(type):
pass
2.如果像压迫切换产生类的元类的话只通过继承是不可以的,必须通过关键字的形式才可以进行转型
class MyClass(metaclass = MeMetaClass):
pass
3.__init__实例化
class MyMetaClass(type):
def __init__(self, what, bases=None, dict=None):
print('自己')
print('what', what) # 类名
print('bases', bases) # 类的父类
print('dict', dict) # 类的名称空间
if not what.istitel():
print('首字母必须大写如果不大写直接剔除')
raise Exception('首字母必须大写如果不大写直接剔除')
super().__init__(what, bases, dict)
元类的进阶操作
1.对象加括号执行产生的对象类内部加括号就可以操控内部对象
2.类加括号执行产生该类的元类里面的双下call
3.实例化对象并操控
class MyMetaClass(type):
def __call__(self, *args, **kwargs):
print('from __call__') # from __call__
if args:
raise Exception('需要根据形参传实参')
super().__call__(*args, **kwargs) # from __call__
class MyCalss(metaclass=MyMetaClass):
def __init__(self, name, age):
self.name = name
self.age = age
print('from __init__') # from __init__
obj1 = MyCalss('joseph', 21)
obj2 = MyCalss(name='joseph', age=21)
双下new方法
"""
类产生对象的步骤
1.产生一个空对象
2.自动触发__init__方法实例化对象
3.返回实例化好的对象
"""
__new__方法专门用于产生空对象 骨架
__init__方法专门用于给对象添加属性 血肉
如果在类中重写了__new__()方法, 我们可以通过 return 出一个实例, 该实例可以直接是 object 实例出来的对象, 也可以是当前类的父类实例出来的对象,__new__() 用于创建实例,所以该方法是在实例创建之前被调用,它是类级别的方法,是个静态方法