博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
面向对象之高级篇 反射,元类
阅读量:5011 次
发布时间:2019-06-12

本文共 4719 字,大约阅读时间需要 15 分钟。

今日内容

1.反射

2.元类

3.单列模式

 

一 反射(反省)

什么是反省:

  通过字符串来反射,映射到对象,类的属性上,英文中叫反省(自省)

面向对象中的反省,指的是一个对象必须具备,发现自身属性,以及修改自身属性的能力:

一个对象在设计初期,可能考虑不够周全,后期需要删除或者修改已经存在的属性,和增加属性

反省就是通过字符串啦操控对象属性

涉及到的有四种方法:

   hasattr:判断是否存在某个属性

   getattr:获取某个属性的值

   setattr:新增或者修改某个属性

   delattr:删除某个属性

注意:只要点能访问的属性,以上四个方法都能操作

案例:四个方法

1 class People: 2     def __init__(self,name,age): 3         self.name = name 4         self.age = age 5  6     def run(self): 7         print('%s is running'%self.name) 8  9 pe = People('zy',19)10 11 print(pe.__dict__)#{'name': 'zy', 'age': 19}12 13 print(pe.name) # pe.__dict__['name']14 15 pe.name = 'zhangyu' # pe.__dict__['name] = 'zhangyu'16 17 del pe.name # del pe.__dict__['name']18 19 四个方法20 查看是否在里面21 print(hasattr(pe,'name')) # 'name' in pe.__dict__22 23 获取值24 print(getattr(pe,'name')) # pe.__dict__['name']25 26 通过键获取值要是键不存在的话,会报错,但你也可以加上一个None让他不报错,打印None27 print(getattr(pe,'xxx',None)) # pe.__dict__['xxx']28 29 可以修改值30 setattr(pe,'name','zhangyu') # pe.__dict__['name']='zhnagyu'31 print(pe.name)32 print(pe.__dict__)# {'name': 'zhangyu', 'age': 19}33 34 删除35 把name这个键值对删除了36 delattr(pe,'name')37 print(pe.__dict__)
View Code

 

反射的案例:

1 class Ftp: 2     def get(self): 3         print('get') 4  5     def put(self): 6         print('put') 7  8     def login(self): 9         print('login')10 11     def run(self):12         while True:13             cmd = input('>>>').strip()14             if hasattr(self,cmd):15                 method = getattr(self,cmd)16                 method()17             else:18                 print('输入的方法不存在')19 20 obj = Ftp()21 22 obj.run()
View Code

 

二 元类

元类简介:

  元类是什么,用于创建类的类,万物皆对象,类也是对象,

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

  实例化产生的,默认情况下所有类的元类都是type

案例:

  

class OldboyTeacher:    def __init__(self,name,age,sex):        self.name = name        self.age = age        self.sex = sex    def score(self):        print('%s is scoring'%self.name)t = OldboyTeacher('zy',19,'male')print(type(t))print(type(OldboyTeacher))对象t 是调用OldboyTeacher类得到的,如果说一切皆对象的话,那么OldboyTeacher也是一个对象,只要是对象,都是调用一个类实例化得到的,即OldboyTeacher = 元类,内置的元类是type

 

为什么要学习元类:

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

  类也是对象,也有自己的类,我们的需求是创建类对象做一些限制

  想到了初始化方法,我们只要找到类对象的类(元类)覆盖其中init方法就能实现需求

  但是我们不能修改源代码,所以应该继承type来编写自己的元类,同时覆盖init来完成需求

 案例:

1 """ 2 只要继承了type 那么这个类就变成了一个元类 3 """ 4 # 定义了一个元类 5 class MyType(type): 6     def __init__(self,clss_name,bases,dict): 7         super().__init__(clss_name,bases,dict) 8         print(clss_name,bases,dict) 9         if not clss_name.istitle():10             raise Exception("你丫的 类名不会写...")11 12 # 为pig类指定了元类为MyType13 class Pig(metaclass=MyType):14     pass15 16 class Duck(metaclass=MyType):17     pass
View Code

 

元类中的call方法:

  当你调用类对象时会自动珍惜元类中的__call__方法 ,并将这个类本身作为第一个参数传入,以及后面的一堆参数

  覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建

  并返回其返回值

 

使用场景: 

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

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

案例:实现将对象的所有属性名称转为大写

1 class MyType(type): 2     def __call__(self, *args, **kwargs): 3         new_args = [] 4         for a in args: 5             new_args.append(a.upper()) 6  7         print(new_args) 8         print(kwargs) 9         return super().__call__(*new_args,**kwargs)10 11 12 class Person(metaclass=MyType):13     def __init__(self,name,gender):14         self.name = name15         self.gender = gender16 17 p = Person(name="jack",gender="woman")18 print(p.name)19 print(p.gender)
View Code

注意: 一旦覆盖了call必须调用父类的call方法来产生对象并返回这个对象

 

元类中的new方法:

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

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

 

案例:

1 class Meta(type): 2  3     def __new__(cls, *args, **kwargs): 4         print(cls) # 元类自己 5         print(args) # 创建类需要的几个参数  类名,基类,名称空间 6         print(kwargs) #空的  7         print("new run") 8         # return super().__new__(cls,*args,**kwargs) 9         obj = type.__new__(cls,*args,**kwargs)10         return obj11     def __init__(self,a,b,c):12         super().__init__(a,b,c)13         print("init run")14 class A(metaclass=Meta):15     pass16 print(A)
View Code

总结:

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

 

三 单列模式

什么是单列模式: 

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

  例如:MVCMTV等
  单例:指的是一个类产生一个对象
  为什么要使用单例:单例是为了节省 资源,当一个类的所有对象属性全部相同时,则没有必要创建多个对象

 

元类实现案例:

1 # 单例n元类 2 class Single(type): 3     def __call__(self, *args, **kwargs): 4         if hasattr(self,"obj"): #判断是否存在已经有的对象 5             return getattr(self,"obj") # 有就返回 6  7         obj = super().__call__(*args,**kwargs) # 没有则创建 8         print("new 了") 9         self.obj = obj # 并存入类中10         return obj11 12 13 class Student(metaclass=Single):14     def __init__(self,name):15         self.name = name16 17 18 class Person(metaclass=Single):19     pass20 21 # 只会创建一个对象22 Person()23 Person()
View Code

 

转载于:https://www.cnblogs.com/zahngyu/p/11273112.html

你可能感兴趣的文章
Jquery Uploadify3.21.与2.1版本 使用中存在的问题--记录三
查看>>
Linux查看进程的内存占用情况 分类: ubuntu ...
查看>>
[BZOJ 2818]Gcd
查看>>
FORM值传递与地址传递
查看>>
(译)yaml快速教程
查看>>
C:大数相加
查看>>
160. Intersection of Two Linked Lists
查看>>
人生苦短,我用python-- Day11
查看>>
JAVA Bean
查看>>
ehcache memcache redis 三大缓存男高音_转
查看>>
curd_3
查看>>
百度地图API示例之设置地图显示范围
查看>>
Java构造方法、重载及垃圾回收
查看>>
.Net Core AES加密解密
查看>>
Spring Quartz实现任务调度
查看>>
python | 桶排序、冒泡排序、选择排序、去重
查看>>
两个Html页面之间值得传递
查看>>
EasyUI datagrid 的多条件查询
查看>>
Mac升级bash到最新版本
查看>>
利用vagrant打包系统--制作自己的box
查看>>