反射 (reflect)

什么是反射,其实是反省,自省的意思

反射指的是一个对象应该具备,可以检测,修改,增加自身属性的能力

反射就是通过字符串操作属性

设计四个函数,这四个函数就是普通的内置函数,没有下划线,与print等没区别.

hasattr   getattr    setattr    delattrclass Student:def __init__(self,name,age):self.name = nameself.age = agestu = Student('uu',12)
if hasattr(stu,'name'):  # 判断对象是否存在某个属性print(getattr(stu,'name',None))  # 从对象中取出属性,第三个为默认值  当属性不存在时 返回默认值
# 为对象添加新的属性
setattr(stu,'gender','male')
print(stu.gender)# 从对象中删除属性
delattr(stu,'name')
print(stu.name)

使用场景:

  反射其实就是对属性的增删改查,但是如果直接使用内置的__dict__来操作,语法繁琐,不好理解

框架设计方式:
框架代码:

反射被称为框架的基石,为什么?因为框架的设计者,不可能提前知道你的对象到底是怎么设计的,所以你提供给框架的对象,必须通过判断验证之后才能正常使用,判断验证就是反射要做的事情,当然通过__dict__也是可以实现的,其实这些方法也就是对__dict__的操作进行了封装

"""需求:要实现一个用于处理用户的终端指令的小框架"""
# settings# 该文件作为框架的配置文件
# 作为框架的使用者  在配置文件中指定你配合框架的类是哪个
Class_path = 'libs.plugins.WinCmd'

#libs.plugins# class WinCmd:
#
#     def cd(self):
#         print('wincmd切换目录')
#
#     def delete(self):
#         print('wincmd删除')
#
#     def dir(self):
#         print('列出目录')
#
# class LinuxCmd:
#
#     def cd(self):
#         print('Linux切换目录')
#
#     def delete(self):
#         print('Linux删除')
#
#     def ls(self):
#         print('列出目录')

import settings
import importlib
# 框架已经实现的部分
def run(obj):while True:cmd = input('请输入指令:')if cmd == 'exit':break     # 因为无法确定框架使用者是否传入正确的对象所以需要使用反射来检测     # 判断对象是否具备处理这个指令的方法if hasattr(obj,cmd):      # 取出对应的方法res = getattr(obj,cmd)res()  # 执行方法处理指令else:print('nono')print('结束')
# 框架 得根据配置文件拿到需要的类# 从配置中单独拿出来  模块路径和类名称
modles_path,cls_name = settings.Class_path.rsplit('.',1)# 拿到模块
mk = importlib.import_module(modles_path)# 拿到类
cls = getattr(mk,cls_name)# 实例化对象
obj = cls()# 调用框架
run(obj)

如此一来,框架就与实现代码彻底解耦了,只剩下配置文件

元类(metaclass)

元类是什么,用于创建类的类

万物皆对象,类当然也是对象

对象是通过类实例化产生的,如果类也是对象的话,必然类对象也是有另一个类实例化产生的

默认情况下所有类的元类都是type

验证:

class Person:passp = Person()
print(type(Person))  # <class 'type'>

学习元类的目的:

高度的自定义一个类,例如控制类的名字必须以大驼峰的方式来书写

类也是对象,也有自己的类

"""需求:创建类对象做一些限制"""# 定义了一个元类
class MyType(type):def __init__(self,cls_name,bases,dict):super().__init__(cls_name,bases,dict)print(cls_name,bases,dict)if not cls_name.istitle:raise Exception('请遵守规则!')为Pig类指定了元类为MyType
class Pig(metaclass=MyType)pass
#  Pig () {'__module__': '__main__', '__qualname__': 'Pig'}class pig(metaclass=MyType):pass
# 报错  Exception: 请遵守规则!

元类中call方法:

__call__函数的执行时机: 该方法会在调用对象时自动触发执行(对象加括号)

class Foo:def __call__(self,*args,**kwargs):print('run')f = Foo()  # 调用Foo得到f对象
f()  # 调用对象时  触发__call__的执行

通常调用一个普通对象是没有意义的,那__call__在什么时候用呢?

我们说类也是一个对象,那么Foo()是不是也执行了Foo的类中的__call__函数呢?

Foo的类是谁呢? 默认是元类type,通过mateclass来指定为自定义的元类来测试

# 测试
class A(type):def __call__(self, *args, **kwargs):print('run')passpassclass B(metaclass=A):passprint(B())
# 输出   run
# 输出 None

覆盖__call__函数时的注意事项

  第一行输出表明了,调用类B时,的确自动执行了__call__函数,

  第二行输出一个空,这是为什么呢?

  必须明确创建对象的过程: 先创建空对象,执行初始化将属性存储到对象的名称空间中!
  所以在__call__函数中必须完成这两步操作,同时将初始化完成的对象返回给调用者

  一旦覆盖了__call__函数,就必须自己来完成上述的几个步骤

class MyMeta(type):def __init__(self,name,bases,dict):super().__init__(name,bases,dict)print('run')def __call__(self, *args, **kwargs):print('元类 call')print(self)print(args)print(kwargs)return super().__call__(*args,**kwargs)class Dog(metaclass=MyMeta):def __init__(self,name):self.name = namedef __call__(self, *args, **kwargs):print('Dog run')d = Dog('dahuang')
print(d.name)# 输出结果
#run
# 元类 call
# <class '__main__.Dog'>
# ('dahuang',)
# {}
# dahuang

# 必须以关键字的形式传参class Metaclass(type):def __call__(self, *args, **kwargs):if args:raise Exception('必须以关键字的形式传参')return super().__call__(*args,**kwargs)class A(metaclass=Metaclass):def __init__(self,name):self.name = namea = A(name = 'uu')
print(a.name)

元类的new方法

当你要创建类对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后会自动调用__Init__来对这个类进行初始化操作

注意:如果你覆盖了该方法则必须保证,new方法必须有返回值且必须是对应的类对象

class Meta(type):def __new__(cls, *args, **kwargs):print(cls) # 元类自己print(args) # 创建类需要的几个参数  (类名,基类,名称空间)print(kwargs) # 空的print('new run')obj = type.__new__(cls,*args,**kwargs)return objdef __init__(self,a,b,c):super().__init__(a,b,c)print('run')class A(metaclass=Meta):pass# a = A()
print(A)

总结new方法和init方法都可以实现控制类的创建过程,init更简单

使用场景:

  当你想要控制对象的创建过程时,就覆盖call方法

  当你想要控制类的创建过程时,就覆盖init方法

单例设计模式

设计模式用于解决某种固定问题的套路

MVC     MTV

单例:指的是一个类产生一个对象

为什么要用单例:

单例是为了节省 资源,当一个类的所有对象属性全部相同时,则没必要创建多个对象

# 单例n元类
class Single(type):def __call__(self, *args, **kwargs):if hasattr(self,"obj"): #判断是否存在已经有的对象return getattr(self,"obj") # 有就返回
obj = super().__call__(*args,**kwargs) # 没有则创建print("new 了")self.obj = obj # 并存入类中return objclass Student(metaclass=Single):def __init__(self,name):self.name = nameclass Person(metaclass=Single):pass# 只会创建一个对象
Person()
Person()

转载于:https://www.cnblogs.com/KrisYzy/p/11271539.html

面向对象编程 --- 反射相关推荐

  1. Python - 面向对象编程 - 反射 hasattr、getattr、getattr、delattr

    什么是反射 反射的概念是由 Smith 在 1982 年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省) Python 面向对象中的反射 通过字符串的形式操作对象的属性 ...

  2. Java面向对象编程篇6——注解与反射

    Java面向对象编程篇6--注解与反射 1.注解概述 Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制 Java 语言中的类.方法.变量.参数和包等都可 ...

  3. java class对象创建时机_Java面向对象编程-类的声明周期

    第十章 类的生命周期 10.1 Java虚拟机及程序的生命周期 当通过java命令运行一个Java程序时,就启动了一个Java虚拟机进程.Java虚拟机进程从启动到终止的过程,称为Java虚拟机的生命 ...

  4. python面向对象编程的三大特性_Python面向对象总结及类与正则表达式详解

    Python3 面向对象 -------------------------------------------------------------------------------- 一丶面向对象 ...

  5. 问题小结(二)——maven的核心功能、面向对象编程和面向接口编程的区别、抽象类和接口的区别等

    文章目录 1. Java创建对象有哪四种方式? 2. 什么是maven?maven的核心功能有哪些? 3. 什么是MVC?说说分层的好处. 4. Spring的两大核心技术是什么? 5. 什么是IOC ...

  6. Dave Python 练习十五 -- 面向对象编程

    #encoding=utf-8 ### *************** 面向对象编程 ******************** #*********** Part 1: 面向对象编程 ******** ...

  7. javascript 学习笔记之面向对象编程(二):继承多态

    ~~接上篇~~上一篇实现了类的实现以及类成员变量和方法的定义,下面我们来了解下面向对象中两个最重要的特性:继承和多态. 继承 js中同样可以实现类的继承这一面向对象特性,继承父类中的所有成员(变量和属 ...

  8. 编写python程序、创建名为class的数据库_python面向对象编程class1

    python面向对象编程class1 #!/usr/bin/python class clz: ###name="nam330" def __init__(self): self. ...

  9. JAVA的面向对象编程--------课堂笔记

      面向对象主要针对面向过程. 面向过程的基本单元是函数.   什么是对象:EVERYTHING IS OBJECT(万物皆对象)   所有的事物都有两个方面: 有什么(属性):用来描述对象. 能够做 ...

  10. python完全支持面向对象编程_python面向对象编程----009

    本篇内容: 1.反射 2.面向对象编程 3.面向对象三大特性 4.类成员 5.类成员修饰符 6.类的特殊成员 7.单例模式 反射 python中的反射功能是由以下四个内置函数提供:hasattr.ge ...

最新文章

  1. PAT(甲级)2020年春季考试 7-4 Replacement Selection
  2. 20180719 (内置函数68个)
  3. node --- 创建一个Socket服务器
  4. (15)VHDL测试激励编写(复位)
  5. PHP工程师学习计划
  6. UBUNTU开启IPV6
  7. 【2020.2.29更新】高通蓝牙芯片QCC3003,QCC3008 学习视频教材
  8. [培训-DSP快速入门-1]:DSP概述(基本框架、CPU, GPU, FPGA比较,常见型号)
  9. php物联网智能家居系统源代码,基于物联网技术的智能家居控制系统设计方案
  10. 上twitter_如何在Twitter上阻止某人
  11. 正在存储windows支持软件_ibm/lenovoDS3500扩展柜存储管理软件-北京瑞腾世纪科技有限公司...
  12. 你有哪些独到的识人技巧?
  13. Mint-Ui安装及使用办法
  14. sql server中的怎么把数值型转换为字符串
  15. numpy迭代数组nditer、flat
  16. Illegal unquoted character ((CTRL-CHAR, code 13)): has to be escaped using backs
  17. SAP 系统组织结构
  18. vue 所见即所得_用于Vue.js的轻量级所见即所得编辑器
  19. 信用卡当天还款当天刷有风险吗?-民兴
  20. 水滴互助的0.01元“套路”:额外充钱才享保障 交钱被拒后推荐保险

热门文章

  1. 抓住数字经济机遇 新华三助力客户加速转型
  2. 九度OJ 题目1534:数组中第K小的数字(二分解)
  3. Lintcode 730 所有子集的和
  4. 第95天:CSS3 边框、背景和文字效果
  5. 关于 Android Service 的介绍都在这了
  6. 如何估算网站日承受最大访问PV
  7. 总结一下SQL语句中引号(')、quotedstr()、('')、format()在SQL语句中的用法
  8. DAC+DMA+TIM实现音频播放问题记录
  9. Android IPC系列(三):Binder概述
  10. datatable删除行、列