元类

元类

一切源自于一句话: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)

 

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

'''

六:单例模式

 

单例模式就是确保一个类只有一个实例.当你希望整个系统中,某个类只有一个实例时,单例模式就派上了用场.
比如,某个服务器的配置信息存在在一个文件中,客户端通过AppConfig类来读取配置文件的信息.如果程序的运行的过程中,很多地方都会用到配置文件信息,则就需要创建很多的AppConfig实例,这样就导致内存中有很多AppConfig对象的实例,造成资源的浪费.其实这个时候AppConfig我们希望它只有一份,就可以使用单例模式.




实现方式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)

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)

call控制类的调用
class Foo:
  def __call__(self, *args, **kwargs):
      print('================>')
      print(self)
      print(args)
      print(kwargs)


obj1 = Foo()
obj1(1,2,3,a=1,b=2) # 调用对象其实就是在调用对象类中定义的绑定方法__call__
#

# obj2 = int(10)

# obj2()

# obj3 = list([1, 2, 3])

# obj3()
posted @ 2020-08-18 15:43  Οo白麒麟оΟ  阅读(111)  评论(0编辑  收藏  举报