元类
作者:互联网
目录
反射实例案例
对于面向对象之反射,我的理解是你通过输入的方式给出一个指令,我不需要知道你给出的是哪个对象,其中的指令有哪些,我只要管自己输入要执行的指令,有我就执行,没有我就返回指令不存在的提示。
class WinCmd(object):
def ls(self):
print('windows系统正在执行ls命令')
def dir(self):
print('windows系统正在执行dir命令')
def cd(self):
print('windows系统正在执行cd命令')
class LinuxCmd(object):
def ls(self):
print('Linux系统正在执行ls命令')
def dir(self):
print('Linux系统正在执行dir命令')
def cd(self):
print('Linux系统正在执行cd命令')
obj = WinCmd()
obj1 = LinuxCmd()
'''反射提供了一种不需要代码的前提下,操作数据和功能'''
def run(obj):
while True:
cmd = input('请输入您的指令>>>:')
if hasattr(obj,cmd):
func_name = getattr(obj, cmd)
func_name()
else:
print('cmd command not found')
run(obj1)
run(obj)
面向对象的双下方法
面向对象的双下方法被一些人称为魔法方法,因为一些面向对象双下方法在达到某个条件的时候会自动触发,不需要手动调用
# __str__
class person(object):
def __init__(self, name):
self.name = name
def __str__(self):
print('__str__执行')
return '打印时执行__str__'
obj1 = person('king')
print(obj1)
print(person)
'''
在对象被执行打印(print、前端展示)操作的时候自动触发
该方法必须返回字符串类型的数据,不然会报错
主要用于精准的描述对象
'''
# __del__
class person(object):
def __init__(self, name):
self.name = name
def __del__(self):
print(self.name)
obj1 = person('king')
# 执行完成代码为被动
# print(obj1)
# print('哈哈')
# 主动
print(obj1)
del obj1
print('哈哈')
'''
对象被执行(被动、主动)删除操作之后自动执行
被动删除:python解释器会在程序执行完成之后,自动删除内容
主动删除:使用del等删除的关键字手动删除
'''
# __getattr__
class person(object):
def __init__(self, name):
self.name = name
def __getattr__(self, item):
print(f'{item}对象查找不存在')
obj1 = person('king')
print(obj1.age) # None,__getattr__的执行在这个结果出现之前
'''
对象查找(使用)不存在的名字的时候自动触发
'''
# __setattr__
# 主要用于给对象添加属性用的,当对象执行添加属性操作的时候自动触发 >>> obj.变量名=变量值
class person(object):
def __init__(self, name):
self.name = name
def __setattr__(self, key, value):
print('执行了__setattr__')
super().__setattr__(key, value)
'''
当你对__setattr__方法进行操作添加的时候要记得继续再继承一下父类的方法__setattr__不然你的属性添加不到对象的名称空间中
'''
obj1 = person('king')
obj1.age = 18
# print(obj1.age)
print(obj1.__dict__)
# __call__
class person(object):
def __init__(self, name):
self.name = name
def __call__(self, *args, *kwargs):
print('hahaha', args, kwargs)
return 'sdaadssd'
obj1 = person('king')
obj1(1)
'''
用于对象加括号调用的时候自动触发,如果想接受实参,加上形参即可
'''
# __enter__
class person(object):
def __init__(self, name):
self.name = name
def __enter__(self):
print('执行__enter__')
def __exit__(self, exc_type, exc_val, exc_tb): # 一定要加上后面三个参数,在看不到的地方自动传入了四个参数
print('执行__exit__', exc_type, exc_val, exc_tb) # 执行__exit__ None None None
obj1 = person('king')
with obj1 as f: # with程序开始,自动执行__enter__
print('123') # with程序结束,自动执行__exit__
print('321')
'''
__enter__和__exit__必需配合使用
'''
# __getattribute__
class person(object):
def __init__(self, name):
self.name = name
def __getattribute__(self, item):
print(f'{item}',item)
obj1 = person('king')
print(obj1.__dict__) # None 只要一看到对象查找名字(调用数据),就运行__getattribute__
print(obj1.age) # None
print(obj1.name) # None
'''
只要对象查找名字无论名字是否存在都会执行该方法
如果类中有__getattribute__方法 那么就不会去执行__getattr__方法
用了这个方法,就算有这个属性,print打印的结果也是None
'''
笔试题讲解
# 让字典具备据点符查找值的功能
# 1.定义一个类继承字典
class MyDict(dict):
# 做到可以句点符取值
def __getattr__(self, item):
return self.get(item)
# 做到句点符赋值
def __setattr__(self, key, value):
self[key] = value # 对象名称空间中是正常的属性=属性值,而字典中是键值队的形式,因此赋值方式要更改一下
'''对于这个题目要做到区分是名称空间的名字还是数据k:v键值对'''
obj = MyDict({'name': 'jason', 'age': 18})
# 1.具备句点符取v
# print(obj.name)
obj.pwd = 123 # 相当于 正常字典的obj['gender'] = 'male'
'''给字典名称空间添加名字,不是数据k:v'''
print(obj)
2.补全下列代码 使其运行不报错
# 补全下列代码 使其运行不报错
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 ctx:
ctx.do_something()
'''
对于with 对象 as 变量名: 来说对象所属的类中一定要有双下enter和双下exit
对于对象内容所变成的do_something来说,对象内要有do_something方法
'''
元类简介
# 元类
即产生类的类
class MyClass(object):
pass
obj = MyClass()
print(type(obj)) # <class '__main__.MyClass'> type查看的其实是当前对象所属的类名称
print(type(MyClass)) # <class 'type'>
class Student:
pass
print(type(Student)) # <class 'type'>
class Teacher(MyClass):
pass
print(type(Teacher)) # <class 'type'>
'''type就是所有类默认的元类'''
产生类的两种表现形式(本质是一种)
1.class关键字
class C1(object):
pass
print(C1) # <class '__main__.C1'>
2.type元类
type(类名,父类,类的名称空间)
res = type('C1', (), {})
print(res) # <class '__main__.C1'>
'''
学习元类的目的
元类能够控制类的创建 也就意味着我们可以高度定制类的行为
eg:掌握了物品的生产过程 就可以在过程中做任何的额外操作
比如:要求类的名字必须首字母大写
思考在哪里编写定制化代码
类的产生过程目前还比较懵 元类里面的__init__方法
对象的产生过程呢 类里面的__init__方法
方法:由已知推未知
'''
元类的基本使用
'''元类是不能通过继承的方式直接指定的'''
通过关键字参数metaclass修改该类的元类,C1的创建受自己元类的影响
class C1(metaclass=MyTypeClass):
pass
class MyTypeClass(type): # 元类用来定制类的行为(样式)
def __init__(cls, cls_name, cls_bases, cls_dict): # 必须写明4个形参,因为默认传入4个实参
# print(cls, cls_name, cls_bases, cls_dict)
if not cls_name.istitle():
raise Exception("类名的首字母必须大写 你个sd")
super().__init__(cls_name)
class C1(metaclass=MyTypeClass):
school = "清华大学"
class a(metaclass=MyTypeClass):
school = '清华大学'
元类进阶操作
1.回想__call__方法
对象加括号会自动执行产生该对象的类里面的__call__,并且该方法返回什么对象加括号就会得到什么
推导:类加括号会执行元类的里面的__call__该方法返回什么其实类加括号就会得到什么
"""类里面的__init__方法和元类里面的__call__方法执行的先后顺序"""
class MyTypeClass(type):
def __call__(self, *args, **kwargs):
print('__call__ run')
print(args, kwargs)
super(MyTypeClass, self).__call__(*args, **kwargs)
class MyClass(metaclass=MyTypeClass):
def __init__(self, name):
print('__init__')
self.name = name
obj = MyClass('jason')
# call在init前运行
# 定制对象的产生过程
class MyTypeClass(type):
def __call__(self, *args, **kwargs):
if args: # 若args有值表示输入的不是关键字参数
raise Exception("必须全部采用关键字参数")
super().__call__(*args, **kwargs)
class MyClass(metaclass=MyTypeClass):
def __init__(self, name):
self.name = name
'''只要为了展示,传入的值目前拿不出来'''
'''强制规定:类在实例化产生对象的时候 对象的独有数据必须采用关键字参数'''
obj2 = MyClass(name='jason') # 关键字参数是放在kwargs里的
print(type(obj2))
'''
如果你想高度定制类的产生过程
那么编写元类里面的__init__方法
如果你想高度定制对象的产生过程
那么编写元类里面的__call__方法
'''
双下new方法
__new__用于产生空对象(类) 骨架
__init__用于实例化对象(类) 血肉
class MyTypeClass(type):
# def __new__(cls, *args, **kwargs):
# print('__new__ run')
# return super().__new__(cls, *args, **kwargs)
#
# def __init__(cls,cls_name, cls_bases, cls_dict):
# print('__init__ run')
# super().__init__(cls_name, cls_bases, cls_dict)
def __call__(cls, *args, **kwargs):
# 1.产生一个空对象
obj = object.__new__(cls, *args, **kwargs)
# 2.调用init方法实例化
return obj
class MyClass(metaclass=MyTypeClass):
def __init__(self, name):
self.name = name
obj = MyClass('jason')
print(obj)
"""
注意:并不是所有的地方都可以直接调用__new__ 该方法过于底层
如果是在元类的__new__里面 可以直接调用
class Meta(type):
def __new__(cls, *args, **kwargs):
obj = type.__new__(cls,*args,**kwargs)
return obj
如果是在元类的__call__里面 需要间接调用
class Mate(type):
def __call__(self, *args, **kwargs):
obj = object.__new__(self) # 创建一个空对象
self.__init__(obj,*args,**kwargs) # 让对象去初始化
return obj
"""
标签:__,name,self,元类,print,class,def 来源: https://www.cnblogs.com/smallking-keep/p/16133326.html