"""
call
调用的意思 ? 在在对象被调用时 执行
函数 类
自定义元类 的目的 ? 1.可以通过call 来控制对象的创建过程 ? 2.可用控制类的创建过程 """
自定义一个元类 元类也是一个类 但是需要继承type
class MyMeta(type):?self 表示要创建对象的那个类(Person) *args是调用Person类时传入的参数?? def __call__(self, *args, **kwargs):?? print("MyMte中的 call run‘") print(*args) #Person的参数?print(self) #person 类?下面的三步是固定写法 一个模板 只要你需要控制对象的创建过程 就应该先把模板写出来?1.创建空对象?? obj = object.__new__(self)?2.调用初始化方法?? self.__init__(obj,*args,**kwargs)?3.得到一个完整的对象?? return obj?修改Person类的元类为MyMeta?class Person(metaclass=MyMeta):?? def __init__(self,name,age):? self.name = name? self.age = age?? def __call__(self, *args, **kwargs): #程序运行的就会自动运行? print("call run...")?调用Person这个对象时 执行的是 Person的类(type)中__call__ 方法?p = Person("张三",80)?print(p)?当调用对象时 会执行该对象所属类中的__call__方法?p()?print(p.name)print(p.age)??
练习:
class My(type): obj = None def __call__(self, *args, **kwargs): if not My.obj: print(‘yes‘) obj = object.__new__(self) self.__init__(obj,*args, **kwargs) My.obj = obj return My.obj?class Orange(metaclass=My): def __init__(self,name,type_1,price): self.name = name self.type = type_1 self.price = price def forma(self): print(self.__dict__)o1 = Orange(‘金水橘‘,‘橘子‘,40)o1.forma()
练习2:
class CarMeta(type):? def __call__(self, *args, **kwargs):? if len(args) < 3: raise ValueError("必须包含三个参数.....") obj = object.__new__(self) self.__init__(obj,*args,**kwargs)? if not("production_date" in obj.__dict__ and "engine_number" in obj.__dict__ and "capacity" in obj.__dict__): raise ValueError("必须包含 生产日期,发动机编号,载客容量") return obj??class BigCar(metaclass=CarMeta):? def __init__(self,production_date,engine_number,capacity):? self.production_date = production_date? self.engine_number = engine_number? self.capacity = capacity?c = BigCar("2018 12 21","e-1-3-q-f",5)print(c)
要控制类的创建过程 只要找到类所属的类 中的init即可
class MyMeta(type):?1. self 刚建出来的类2. 第二个 类的名字3. 第三个 类的父类们 元组4. 第四个 这个类传进来的名称空间? def __init__(self ,class_name ,bases ,namespace): print("============================")?# print(self.__dict__)?# 我要控制 类的名字 必须 是大写开头? if not class_name.istitle(): print("类名 必须大写开头...... ")?# 该代码是主动抛出异常? raise TypeError("类名 必须大写开头...... ")?# 要空类的创建 必须包含__doc__这个属性? if not self.__doc__: raise TypeError("类中必须有文档注释.....")? pass?class Student(metaclass=MyMeta): # Student = MyMeta("Student",(object,),{}) """ 这是文档注释 可以通过__doc__来获取 这是一个学生类 """?# 在类的__init__中可以控制该类对象的创建过程? def __init__(self ,name): print("-----------------------") print(self.__dict__) self.name = name?print(Student.__doc__)
元类使用总结:
""" 元类是用于创建类的类 学习元类是为了 能控制类的创建过程 以及 类实例化对象的过程
一. 控制类的创建过程 ? 1.创建一个元类 (需要继承type) ? 2.覆盖init方法 该方法 会将新建的类对象 类名 父类们 名称空间 都传进来 , ? 可以利用这些信息在做处理 ? 3.对于需要被控制的类 需要指定metaclass 为上面的元类
二. 控制类实例化对象的过程 ? 1.创建一个元类 (需要继承type) ? 2.覆盖call方法 会将 正在实例化对象的类 调用类是传入的参数 都传进来 ? 3.在call方法中 必须要先编写模板代码 ? 3.1创建空对象 ? 3.2调用类的init方法来初始化这个空对象 ? 3.3返回该对象 ? 4.加入你需要控制的逻辑
类的三个组成部分 类名 父类们 名称空间
元类 -> 实例化产生 -> 类 -> 实例化产生 -> 对象
"""
练习:
组合创建类的创建对象的技巧
class My(type): def __init__(self,a,b,c): if not a.istitle(): print(‘首字母注意大写‘) raise TypeError(‘类名开头必须大写‘) if not a.__doc__: print(‘注释为空‘) raise TypeError(‘请添加注释‘) obj = None def __call__(self, *args, **kwargs): print(‘yes‘) if not My.obj: obj = object.__new__(self) self.__init__(obj,*args, **kwargs) My.obj = obj return My.objclass Tree(metaclass=My): def __init__(self,name,age): self.name = name self.age = age def breath(self): print(‘这颗%s的%s的大树很粗壮‘%(self.age,self.name))t1=Tree(‘衫树‘,30)print(t1)t2=Tree(‘衫树‘,30)print(t2)t1.breath()
单例
""" ? 单例模式 ? 一种设计模式(套路)
单个实例 ? 一个类如果只有一个实例 那么该类称之为单例
为什么需要单例
当要处理的数据全部相同时,比如打印机复印文件时
"""
代码1:
?class Printer(): """ 这是一个单例类 请不要直接实例化 使用get方法来获取实例 """? obj = None def __init__(self,name,brand,type): self.name = name self.brand = brand self.type = type? def printing(self,text): print("正在打印 %s" % text)
以下三个对象 的数据完全相同 但是却 占用三分内存空间
p1 = Printer("ES005","爱普生","彩色打印机")?p2 = Printer("ES005","爱普生","彩色打印机")?p3 = Printer("ES005","爱普生","彩色打印机")
用类调用:
obj = None #定义了类的属性 @classmethod def get_printer(cls): if not cls.obj: obj = cls("ES005","爱普生","彩色打印机") cls.obj = obj print("创建了新的对象")? return cls.obj
通过该方法来获取对象 可以保证只有一个对象
p = Printer.get_printer()print(p)?p = Printer.get_printer()print(p)?p = Printer.get_printer()print(p)?p = Printer.get_printer()print(p)# 内存地址都相同
通过该方法来获取对象 可以保证只有一个对象
但是这还不够 因为 还是可以通过调用类产生新对象
就应该使用元类 来控制实例化的过程 call
在call 中编写代码 保证每次调用call 都返回同一个实例 即可
现在要处理问题就是 如何能够限制该类 只能实例化一个对象
元类
代码2:
class My(type): obj = None def __call__(self, *args, **kwargs): if not My.obj: obj = object.__new__(self) self.__init__(obj, *args, **kwargs) My.obj = obj return My.obj class Printer(metaclass=My): """ 这是一个单例类 请不要直接实例化 使用get方法来获取实例 """ def __init__(self,name,brand,type): self.name = name self.brand = brand self.type = typedef printing(self,text): print("正在打印 %s" % text) p1 = Printer("ES005","爱普生","彩色打印机")p2 = Printer("ES005","爱普生","彩色打印机")?print(p1)print(p2)#内存地址全部一样p1.printing("一本小说....")
元类的思想就是控制对象,所有对象全部都要在call走一遍,才能返回到类里使用。因此在第一次经过元类时,元类就通过赋值给固定死了,以后都不会再初始化了。
了解:
代码1:
class MyMeta(type):?# 用于新建类对象? def __new__(cls, *args, **kwargs): print("new run")?print(MyMeta)?print(*args)?调用type通过的__new__方法来创建一个空的类对象 已经将三个组成部分都放到类对象中了? res = type.__new__(cls,*args) return res? def __init__(self,class_name,bases,namespace): print("init run") print(self)???class Student(metaclass=MyMeta): pass?print(Student)
""" new 与 init的区 new 比init先执行 其作用是创建一个空的类对象 作为一个类对象 必须具备是三个组成部分 所以调用type中的new来完成组装 得到这个类对象后需要将其返回 以供init来使用
"""
原文地址:https://www.cnblogs.com/wang-kai-1994/p/10167241.html