面向对象,元类,控制类,对象的创建
Posted wang-kai-1994
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象,元类,控制类,对象的创建相关的知识,希望对你有一定的参考价值。
call
调用的意思 ? 在在对象被调用时 执行
函数 类
自定义元类 的目的 ? 1.可以通过call 来控制对象的创建过程 ? 2.可用控制类的创建过程 """
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)
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.obj
class 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 = type
def printing(self,text):
print("正在打印 %s" % text)
p1 = Printer("ES005","爱普生","彩色打印机")
p2 = Printer("ES005","爱普生","彩色打印机")
?
print(p1)
print(p2)
#内存地址全部一样
p1.printing("一本小说....")
元类的思想就是控制对象,所有对象全部都要在call走一遍,才能返回到类里使用。因此在第一次经过元类时,元类就通过赋值给固定死了,以后都不会再初始化了。
了解:
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来使用
以上是关于面向对象,元类,控制类,对象的创建的主要内容,如果未能解决你的问题,请参考以下文章