python面向对象(反射、内置方法、元类)
一 反射
# 静态语言:在执行前就定义好数据类型 # var x int=8 # 动态语言:在执行的时候,才识别数据类型 # x = 8 # 什么是反射? # 指的是在程序运行过程中可以“动态”获取对象的信息 # 为何要用反射? # 函数调用对象时,不知道对象下面,有哪些属性,所以要用到反射 # 如何实现反射?----》用字符串来操作对象的属性和方法 class People: def __init__(self, name, age): self.name = name self.age = age def say(self): print('我的名字:{},年龄是{}!'.format(self.name, self.age)) obj = People('lq', 19) # 1.先通过dir查看某一个对象下可以.出哪些属性来 print(dir(obj)) # 对象含有的属性列表 # 2、可以通过字符串反射到真正的属性上,得到属性值 print(obj.__dict__['name']) # lq print(obj.__dict__[dir(obj)[-2]]) # lq # 四个内置函数的使用:通过字符串来操作属性值 # 1、hasattr() print(hasattr(obj, 'name')) # True或False,看该对象下有没有该属性 # 2、getattr() print(getattr(obj, 'name')) # 获取属性值 # lq # 3、setattr() setattr(obj, 'name', 'xiaobao') # 更改属性值 print(obj.name) # xiaobao # 4、delattr() delattr(obj, 'name') print(obj.__dict__) # 不在含有就'name'属性
# 方法的调用 res1 = getattr(obj, 'say') res2 = getattr(People, 'say') print(res1) # obj.say() print(res2) # People.say()
# 例(反射) class Ftp: def put(self): print('正在执行上传功能') def get(self): print('正在执行下载功能') def interactive(self): choice = input('请输入:') # 字符串,'put' if hasattr(self, choice): getattr(self, choice)() # choice是字符串 else: print('输入的指令不存在') obj = Ftp() obj.interactive() ''' 请输入:get 正在执行下载功能 '''
二 内置方法
# 1、什么是内置方法? # 定义在类内部,以__开头并以__结果的方法 # 特点:会在某种情况下自动触发执行,作用和类下面的__init__作用一样 # 2、为何要用内置方法? # 为了定制化我们的类or对象 # 3、如何使用内置方法 # __str__:在打印对象时会自动触发,然后将返回值(必须是字符串类型)当做本次打印的结果输出 class People: def __init__(self, name, age): self.name = name self.age = age def __str__(self): print('hahah') return '我叫{},今年{}'.format(self.name, self.age) obj = People('lq', 19) print(obj) # 可以直接打印对象,不在显示内存地址 ''' hahah 我叫lq,今年19 ''' # __del__:在清理对象时触发,会先执行该方法 class People: def __init__(self, name, age): self.name = name self.age = age self.x = open('a.txt', mode='w') def __del__(self): print('hahah') # 发起系统调用,告诉操作系统回收相关的系统资源 self.x.close() obj = People('lq', 19) print('----->') ''' -----> 程序运行完了,回收内存后,再触发__del__方法 hahah '''
三 元类
1、什么是元类
一切皆为对象
什么是元类?
元类就是用来实例化产生类的类
关系:元类---》实例化--》类(People)-->实例化--》对象(obj)
class People: def __init__(self, name, age): self.name = name self.age = age def say(self): print('我叫{},今年{}'.format(self.name, self.age)) # 如何得到对象 # obj=调用类() obj = People('xiaobao', 6) print(type(obj)) # <class '__main__.People'> # 如何说类也是对象 # People=调用类() # 查看内置的元类: # 1、type是内置的元类 # 2、我们用class关键字定义的所有的类以及内置的类都是由内置的元类type帮我们实例化产生 print(type(People)) # <class 'type'> print(type(int)) # <class 'type'>
2、class关键字创造类People的步骤
# 类有三大特征: # 1、类名 class_name = 'People' # 2、类的基类 class_bases = (object,) # 3、执行类体代码拿到类的名称空间 class_dict = {} class_body = ''' def __init__(self, name, age): self.name = name self.age = age def say(self): print('我叫{},今年{}'.format(self.name, self.age)) ''' exec(class_body, {}, class_dict) print(class_dict) # {'__init__': <function __init__ at 0x0000011D742A9280>, 'say': <function say at 0x0000011D743A24C0>} # 4、调用元类 People = type(class_name, class_bases, class_dict) print(People) # <class '__main__.People'>
3、如何自定义元类来控制类的产生
class Mymeta(type): # 只有继承了type类的类才是元类 def __init__(self, x, y, z): print('run---') print(self) print(x) print(y) print(z) # 当前所在的类,调用类时所传入的参数 def __new__(cls, *args, **kwargs): # 造Mymeta的对象 print('run2222') print(cls, args, kwargs) # <class '__main__.Mymeta'> # ('People', (), {'__module__': '__main__', '__qualname__': 'People', # '__init__': <function People.__init__ at 0x0000010D59172040>, # 'say': <function People.say at 0x0000010D59172670>}) # {} # return super().__new__(cls,*args,**kwargs) # 继承父类 return type.__new__(cls, *args, **kwargs) # 第一步产生空对象的来源 # People=Mymeta(class_name,class_bases,class_dic) # 调用Mymeta发生三件事 # 1、先造一个空对象--》People,调用类内的__new__方法 # 2、调用Mymeta这个类内的__init__方法,完成初始化对象的操作 # 3、返回初始化好的对象 class People(metaclass=Mymeta): def __init__(self, name, age): self.name = name self.age = age def say(self): print('我叫{},今年{}'.format(self.name, self.age)) # 强调: # 只要是调用类,那么会一次调用 # 1)、类内的__new__ # 2)、类内的__init__
4、__call__
class Foo: def __init__(self, x, y): self.x = x self.y = y def __call__(self, *args, **kwargs): print('---->', args, kwargs) return 123 obj = Foo(1, 2) res = obj(1, 2, 3, a=4, b=5, c=6) # 对象可被调用 print(res) # 应用:如果想让一个对象可以加括号调用,需要在该对象的类中添加一个方法__call__ # 总结: # 对象()---》类内的__call__ # 类()---》自定义元类内的__call__ # 自定义元类()---》内置元类__call__
5、自定义元类控制类的调用---》类的对象的产生
class Mymeta(type): # 只有继承了type类的类才是元类 def __call__(self, *args, **kwargs): # 1、Mymeta.__call__函数内会先调用People内的 __new__ people_obj = self.__new__(self) # 2、Mymeta.__call__函数内会调用People内的__init__ self.__init__(people_obj, *args, **kwargs) # 3、Mymeta.__call__函数内会返回一个初始化好的对象 return people_obj # 类的产生 # People=Mymeta()--> type.__call__--->干了三件事 # 1、type.__call__函数内会先调用Mymeta内的__new__ # 2、type.__call__函数内会调用Mymeta内的__init__ # 3、type.__call__函数内会返回一个初始化好的对象 class People(metaclass=Mymeta): def __init__(self, name, age): self.name = name self.age = age def say(self): print('我叫{},今年{}'.format(self.name, self.age)) def __new__(cls, *args, **kwargs): # 产生真正的对象 return object.__new__(cls)
6、属性查找
# 属性查找的原则:对象---》类---》父类
# 切记:父类 不是 元类
# 1--》2--》3--》4--》5--》6
四 元类总结
类是元类的实例化:
1、造空对象,就是元类来造空对象,元类调用自己__new__
2、初始化空对象,就是元类调用自己的__init__方法
__new__和__init__方法都是在__call__方法下,__new__在__init__
3、返回初始化好的对象,就方法__call__的返回值
五 更多反射和魔法方法,看下文
https://www.cnblogs.com/liuqingzheng/articles/9949568.html
分类:
python面向对象编程
标签:
python
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用