一切皆对象
1.都可以被引用
2.都可以当作函数的参数传入
3.都可以当作函数的返回值
4.都可以当作容器类的元素
类其实也是一个对象,那么是谁创建的它呢?
元类是什么
创建类的类称之为元类。
定义类的两种方式:
方式一:class
方式二:type
类的三要素:1.类名。2.类的基类们。 3.类的名称空间
# 用调用的方式创建一个类
class_name = 'Chinese'
class_bases = (object,)
class_body = """
country = 'china'
def __init__(self,name,age):
self.name = name
self.age = age
def talk(self):
print('%s is talking' %self.name)
"""
class_dic = {}
exec(class_body,globals(),class_dic)
Chinese = type(class_name,class_bases,class_dic)
既然类是元类实例化出来的,那么我们就来研究一下这个元类
自定义元类来控制类的创建
既然类是由元类创建的,在创建时会自动执行__init__方法,那么可以在元类中的__init__方法添加一些逻辑来控制类的创建。
首先我们自定义一个元类继承type来重写__init__方法
import re
class Mymeta(type):
def __init__(self, class_name, class_base, class_dic):
if not re.match('[A-Z].*?', class_name):
raise TypeError('类的首字母必须大写')
if not class_dic['__doc__'].strip():
raise TypeError('类必须要有注释,且注释不能为空')
super().__init__(class_name, class_base, class_dic)
class Chinese(metaclass=Mymeta): # 制定创建这个类的元类
"""
123
"""
def __init__(self):
pass
上面的例子中,在创建Chinese这个类时,就强制约束了首字母大写和必须写注释
自定义元类来看看类的实例化底层原理
__call__方法: obj() (对象可以被调用),实际上是执行类中的__call__方法;
class Chinese:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('----')
p = Chinese()
p() # p.__call__()
那么类实例化的过程 : obj = c ls() 实际上就是调用类的过程,也就是执行元类中的__call__方法;
我们通过重写元类中的__call__方法来控制类的实例化行为。
class Mymeta(type):
def __init__(self, class_name, class_base, class_dic):
super().__init__(class_name, class_base, class_dic)
def __call__(self, *args, **kwargs): # 重写__call__方法
# print(self)
# print(args)
# print(kwargs)
obj = object.__new__(self) # 先造一个空对象
self.__init__(obj, *args, **kwargs) # 初始化对象
return obj # 把对象返回
class Chinese(metaclass=Mymeta):
def __init__(self, name, age):
self.name = name
self.age = age
p = Chinese('shi', age=18) # p.__call__()
print(p.__dict__)
上面代码中我们重写了元类的__call__方法,可以了解到创建对象底层的实现原理
自定义元类来控制类的实例化行为的应用
既然知道了类的实例化原理,那么我们来写一个单例模式
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
class Mymeta(type):
def __init__(self, class_name, class_base, class_dic):
super().__init__(class_name, class_base, class_dic)
self.__instance = None
def __call__(self, *args, **kwargs): # 重写__call__方法
if not self.__instance:
obj = object.__new__(self) # 先造一个空对象
self.__init__(obj, *args, **kwargs) # 初始化对象
self.__instance = obj
return self.__instance # 把对象返回
class Mysql(metaclass=Mymeta):
def __init__(self):
pass
obj1 = Mysql() # p.__call__()
obj2 = Mysql()
print(id(p1), id(p2))
以上例子中,实现了单例模式,防止创建多个相同的对象占用内存空间,极大的节省了空间
其实要单纯的解决单例模式,重写类的__new__方法就可以
class Mysql:
def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
cls._instance = super().__new__(cls)
return cls._instance
obj1 = Mysql()
obj2 = Mysql()
print(id(obj1), id(obj2))