面向对象,元类,控制类,对象的创建

Posted wang-kai-1994

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象,元类,控制类,对象的创建相关的知识,希望对你有一定的参考价值。

"""

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.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走一遍,才能返回到类里使用。因此在第一次经过元类时,元类就通过赋值给固定死了,以后都不会再初始化了。

 

 

 

了解:

代码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的区 newinit先执行 其作用是创建一个空的类对象 作为一个类对象 必须具备是三个组成部分 所以调用type中的new来完成组装 得到这个类对象后需要将其返回 以供init来使用

"""

























































































































































































































































以上是关于面向对象,元类,控制类,对象的创建的主要内容,如果未能解决你的问题,请参考以下文章

python 面向对象编程 之 元类

Python----面向对象---自定义元类控制类的实例化行为

面向对象高级C(元类补充及单例模式(待补充))

元类(metaclass)

(转)元类metaclass

Python全栈开发之9面向对象元类以及单例