面向对象之元类等相关内容-34

元类

# 一切源自于一句话:python中一切皆为对象
# 一:元类介绍
"""
​
# 元类=》OldboyTeacher类=》obj
class OldboyTeacher(object):
  school = 'oldboy'
​
  def __init__(self, name, age):
      self.name = name
      self.age = age
​
  def say(self):
      print('%s says welcome to the oldboy to learn Python' % self.name)
​
​
obj = OldboyTeacher('egon', 18) # 调用OldboyTeacher类=》对象obj
#                                 调用元类=》OldboyTeacher类
​
# print(type(obj))
print(type(OldboyTeacher))
# 结论:默认的元类是type,默认情况下我们用class关键字定义的类都是由type产生的
"""
​
# 二:class关键字底层的做了哪些事
'''
# 1、先拿到一个类名
class_name = "OldboyTeacher"
​
# 2、然后拿到类的父类
class_bases = (object,)
​
# 3、再运行类体代码,将产生的名字放到名称空间中
class_dic = {}
class_body = """
school = 'oldboy'
​
def __init__(self, name, age):
  self.name = name
  self.age = age
​
def say(self):
  print('%s says welcome to the oldboy to learn Python' % self.name)
"""
exec(class_body,{},class_dic)
exec方法是将类体代码转换成字典的形式 参数为 类体代码、空字典、需要导出的字典
# print(class_dic)
​
# 4、调用元类(传入类的三大要素:类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名OldboyTeacher,oldboyTeacher就是我们用class自定义的那个类
OldboyTeacher = type(class_name,class_bases,class_dic)
'''
​
# 三:自定义元类
'''
class Mymeta(type): # 只有继承了type类的类才是自定义的元类
  pass
​
​
class OldboyTeacher(object, metaclass=Mymeta):
  school = 'oldboy'
​
  def __init__(self, name, age):
      self.name = name
      self.age = age
​
  def say(self):
      print('%s says welcome to the oldboy to learn Python' % self.name)
​
​
# 1、先拿到一个类名:"OldboyTeacher"
# 2、然后拿到类的父类:(object,)
# 3、再运行类体代码,将产生的名字放到名称空间中{...}
# 4、调用元类(传入类的三大要素:类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名OldboyTeacher,oldboyTeacher就是我们用class自定义的那个类
OldboyTeacher = Mymeta("OldboyTeacher",(object,),{...})
'''
​
# 四:自定义元类来控制OldboyTeacher类的产生
'''
import re
​
​
class Mymeta(type): # 只有继承了type类的类才是自定义的元类
  def __init__(self, class_name, class_bases, class_dic):
      # print(self) # 类<class '__main__.OldboyTeacher'>
      # print(class_name)
      # print(class_bases)
      # print(class_dic)
​
      if not re.match("[A-Z]", class_name):
          raise BaseException("类名必须用驼峰体")
​
      if len(class_bases) == 0:
          raise BaseException("至少继承一个父类")
​
      # print("文档注释:",class_dic.get('__doc__'))
      doc=class_dic.get('__doc__')
​
      if not (doc and len(doc.strip()) > 0):
          raise BaseException("必须要有文件注释,并且注释内容不为空")
​
# OldboyTeacher = Mymeta("OldboyTeacher",(object,),{...})
class OldboyTeacher(object,metaclass=Mymeta):
  """
  adsaf
  """
​
  school = 'oldboy'
​
  def __init__(self, name, age):
      self.name = name
      self.age = age
​
  def say(self):
      print('%s says welcome to the oldboy to learn Python' % self.name)
​
'''
​
# 五:自定义元类来控制OldboyTeacher类的调用
'''
import re
​
​
class Mymeta(type): # 只有继承了type类的类才是自定义的元类
  def __init__(self, class_name, class_bases, class_dic):
      # print(self) # 类<class '__main__.OldboyTeacher'>
      # print(class_name)
      # print(class_bases)
      # print(class_dic)
​
      if not re.match("[A-Z]", class_name):
          raise BaseException("类名必须用驼峰体")
​
      if len(class_bases) == 0:
          raise BaseException("至少继承一个父类")
​
      # print("文档注释:",class_dic.get('__doc__'))
      doc = class_dic.get('__doc__')
​
      if not (doc and len(doc.strip()) > 0):
          raise BaseException("必须要有文件注释,并且注释内容不为空")
​
  # res = OldboyTeacher('egon',18)
  def __call__(self, *args, **kwargs):
      # 1、先创建一个老师的空对象
      tea_obj = object.__new__(self)
      # 2、调用老师类内的__init__函数,然后将老师的空对象连同括号内的参数的参数一同传给__init__
      self.__init__(tea_obj, *args, **kwargs)
      tea_obj.__dict__ = {"_%s__%s" %(self.__name__,k): v for k, v in tea_obj.__dict__.items()}
​
      # 3、将初始化好的老师对象赋值给变量名res
      return tea_obj
​
​
# OldboyTeacher = Mymeta("OldboyTeacher",(object,),{...})
class OldboyTeacher(object, metaclass=Mymeta):
  """
  adsaf
  """
​
  school = 'oldboy'
​
  #           tea_obj,'egon',18
  def __init__(self, name, age):
      self.name = name # tea_obj.name='egon'
      self.age = age # tea_obj.age=18
​
  def say(self):
      print('%s says welcome to the oldboy to learn Python' % self.name)
​
​
res = OldboyTeacher('egon', 18)
print(res.__dict__)
# print(res.name)
# print(res.age)
# print(res.say)
​
# 调用OldboyTeacher类做的事情:
# 1、先创建一个老师的空对象
# 2、调用老师类内的__init__方法,然后将老师的空对象连同括号内的参数的参数一同传给__init__
# 3、将初始化好的老师对象赋值给变量名res
'''
​
# 六:单例模式
​
# settings
HOST = "192.168.11.10"
PORT = 3306
​
# 实现方式1:classmethod
"""
import settings
​
​
class MySQL:
  __instance = None
​
  def __init__(self, ip, port):
      self.ip = ip
      self.port = port
​
  @classmethod
  def singleton(cls):
      if cls.__instance:
          return cls.__instance
      cls.__instance = cls(settings.IP, settings.PORT)
      return cls.__instance
​
​
# obj1=MySQL("1.1.1.1",3306)
# obj2=MySQL("1.1.1.2",3306)
# print(obj1)
# print(obj2)
​
​
obj3 = MySQL.singleton()
print(obj3)
​
obj4 = MySQL.singleton()
print(obj4)
"""
​
# 方式2:元类
"""
import settings
​
​
class Mymeta(type):
  __instance = None
  def __init__(self,class_name,class_bases,class_dic):
      self.__instance=object.__new__(self) # Mysql类的对象
      self.__init__(self.__instance,settings.IP,settings.PORT)
      self代表的是mysql类
​
  def __call__(self, *args, **kwargs):
      if args or kwargs:
          obj = object.__new__(self)
          self.__init__(obj, *args, **kwargs)
          return obj
      else:
          return self.__instance
​
# MySQL=Mymeta(...)
class MySQL(metaclass=Mymeta):
  def __init__(self, ip, port):
      self.ip = ip
      self.port = port
​
​
# obj1 = MySQL("1.1.1.1", 3306)
# obj2 = MySQL("1.1.1.2", 3306)
# print(obj1)
# print(obj2)
​
obj3 = MySQL()
obj4 = MySQL()
​
print(obj3 is obj4)
"""
​
# 方式3:装饰器
"""
import settings
​
def outter(func): # func = MySQl类的内存地址
  _instance = func(settings.IP,settings.PORT)
  def wrapper(*args,**kwargs):
      if args or kwargs:
          res=func(*args,**kwargs)
          return res
      else:
          return _instance
  return wrapper
​
@outter # MySQL=outter(MySQl类的内存地址) # MySQL=》wrapper
class MySQL:
  def __init__(self, ip, port):
      self.ip = ip
      self.port = port
​
​
# obj1 = MySQL("1.1.1.1", 3306)
# obj2 = MySQL("1.1.1.2", 3306)
# print(obj1)
# print(obj2)
​
obj3 = MySQL()
obj4 = MySQL()
print(obj3 is obj4)
"""
​
​
# 了解:属性查找
class Mymeta(type):
   n = 444
​
   # def __call__(self, *args, **kwargs): #self=<class '__main__.OldboyTeacher'>
   #     obj=self.__new__(self)
   #     print(self.__new__ is object.__new__) #True
​
​
class Bar(object):
   # n=333
​
   # def __new__(cls, *args, **kwargs):
   #     print('Bar.__new__')
   pass
​
​
class Foo(Bar):
   # n=222
​
   # def __new__(cls, *args, **kwargs):
   #     print('Foo.__new__')
   pass
​
​
class OldboyTeacher(Foo, metaclass=Mymeta):
   # n=111
​
   school = 'oldboy'
​
   def __init__(self, name, age):
       # self.n=0
       self.name = name
       self.age = age
​
   def say(self):
       print('%s says welcome to the oldboy to learn Python' % self.name)
​
   # def __new__(cls, *args, **kwargs):
   #     print('OldboyTeacher.__new__')
​
​
# obj=OldboyTeacher('egon',18)
# print(obj.n)
​
print(OldboyTeacher.n)
​

 

posted @ 2020-08-19 17:05  投降输一半!  阅读(140)  评论(0)    收藏  举报