什么是元类
与普通类的区别
有什么用
如何使用
# code = """
# global s
# s = 1000
# a = 10
# print(a)
# """
#
# global_dic = {}
# local_dic = {}
#
# exec(code,global_dic,local_dic)
# print(global_dic)
# print(globals())
# print(local_dic)
# 要求你把你一个字符串中出现的名字 存储到一个名称空间中
# text = """
# def func():
# print("func run")
# """
# l_dic = {}
# exec(text,{},l_dic)
# l_dic["func"]()
# """
# 什么是元类
# 一切皆对象
#
#
# 类的类就是元类
# Person 类的元类是type 默认情况下所有类的元类都是type(object除外)
#
#
# """
# import abc # 抽象类
#
# class Person(metaclass=type): # Person == type(..........)
# def __init__(self,name,gender):
# self.name = name
# self.gender = gender
#
# def say_hi(self):
# print("hello im am %s gender is %s" % (self.name,self.gender))
#
# p = Person("xx","xxx")
# # p.say_hi()
#
# # 函数对象
# # ls = [Person]
# # print(ls[0])
# #
# # def f1(cls):
# # print(cls)
# #
# # f1(Person)
#
# print(type(p))
# print(type(Person)) # Person类是有type实例化产生的
#
#
# # 一个类需要包含三个部分
# # 类名称 它的父类 名称空间
#
# class_name = "myclass"
# class_bases = (object,)
# class_namespace = {}
#
# code = """
# school = "xxx"
# def hello(self):
# print(self)
# """
#
# exec(code,{},class_namespace)
# print(class_namespace)
#
# # 创建类的另一种方式
# # 自己来实例化type类
# obj = type(class_name,class_bases,class_namespace)
# type类中肯定有__init__方法
#
class MyMetaClass(type):
# 创建类时 就会自动执行元类中的init方法
def __init__(self,class_name,bases,namespace):
print("MyMetaClass init run")
# 产生一个空的类对象 在调用MyMetaClass中的__init__方法
class ClassA(metaclass=MyMetaClass): # ClassA = type("ClassA",(,),{})
def __init__(self,name):
self.name = name
# 创建出一个CLassA的类对象
class Test:
def __init__(self):
pass
t = Test() #实例化
# 1.创建一个对象的名称空间 空对象
# 2.执行__init__方法来为对象赋初始值
元类中init方法的执行:
class A:
pass
# print(A)
# print(type(A))
namespace = {}
namespace["name"] = "jack"
cls = type("这是一个实例化Type产生的类",(object,),namespace)
#
# print(cls.name)
# print(A)
# 一个类是通过实例化type类产生
# 元类就是用于产生类的类
# 自定义一个元类
# class MyMeta(type):
# # 创建B这个类对象的时候回自动执行
# def __init__(self,a,b,c):
# print("MyMeta init run")
# print(self)
# print(a)
# print(b)
# print(c)
# self.school = "xxx"
#
# class B(metaclass=MyMeta): # B = MyMeta(B,"B",(object,),{......})
# pass
#
# print(B.school)
#
# 必须保证类名大写开头
# class Meta1(type):
# def __init__(self,clas_name,bases,namespace):
# if not clas_name.istitle():
# raise TypeError("类名必须大写开头!")
# # 命名方式 大驼峰
# class person(metaclass=Meta1):
# pass
class Meta2(type):
def __init__(self,cls_name,bases,namespace):
if not self.__doc__:
raise TypeError("必须包含类注释!!")
super().__init__(cls_name,bases,namespace)
#
# 请编写代码 完成 限制一个类必须拥有类注释 否则 不允许创建类
class Animal(metaclass=Meta2):
"""
asas
"""
pass
print(Animal.__doc__)
print(Animal)
__call__方法的执行时机:
__call__
会在某个时间自动执行
class MyMeta(type):
# 会在类对象 准备实例化产生对象时执行
# 该函数可以控制实例化对象的过程
def __call__(self, *args, **kwargs):
print("Mymeta call run!")
# print(self)
# print(args)
# print(kwargs)
#无论你要添加什么功能 只要覆盖了__call__ 就必须把下面两个步骤做了
#1.需要创建一个对象
obj = object.__new__(self)
#2.调用对应init来初始化这个对象
self.__init__(obj,*args,**kwargs)
return obj
# super().__call__(*args,**kwargs)
class Student(metaclass=MyMeta):
def __init__(self,name):
self.name = name
pass
s = Student("xxx") # 是为了创建并实例化一个Student类的对象
print(s)
#__init__ 创建类对象的时候执行 控制类的创建过程
#__call__ 实例化产生对象时执行 控制对象的创建过程 单例模式
单例模式:
单例模式
一种设计模式,MVVM MVC MTV
常推荐书籍见设计模式
要保证一个类只能有一个实例(单例)
为什么这么设计?
目的是为了节省内存开销
如果两个对象的数据一模一样 就没有必要创建新对象 直接使用已有的即可
场景:
当一个类的所有实例数据都完全相同时 则应该设计为单例
音乐播放器类 实例化产生播放器对象
单例的实现方式:
自定义元类 覆盖__cal__ 添加判断逻辑 保证只能实例化一个对象
class MySingleton(type):
obj = None
def __call__(self, *args, **kwargs):
if not self.obj:
# 创建空对象
obj = object.__new__(self)
# 调用初始化方法
self.__init__(obj, *args, **kwargs)
self.obj = obj
return self.obj
class Player(metaclass=MySingleton):
# 默认为空
obj = None
def __init__(self):
print("创建了一个播放器对象....")
def play(self,path):
self.stop()
print("playing...",path)
def stop(self):
print("stop music")
# 用于获取播放器对象
@classmethod
def get_player(cls):
if not cls.obj:
print("创建播放器...")
cls.obj = cls()
return cls.obj
# p = Player("给我一杯忘情水.mp3")
# p.play()
#
#
# p.stop()
# p1 = Player("回首掏.mp3")
# p1.play()
# p = Player()
# p.play("一杯忘情水.")
#
#
p1 = Player.get_player()
p1.play("爱你一万年1.")
p2 = Player.get_player()
p2.play("爱你一万年2.")
# 上述代码 有bug 可以通过直接调用类 来产生新对象
Player().play("我的滑板鞋!")
存在元类时的属性查找顺序:
类自身属性 --> 父类--> object--> type
# class Meta(type):
# s = 1000
#
#
# class A:
# s = 1
# pass
# class B(A,metaclass=Meta):
# # s = 2
# pass
#
# b = B()
# # b.s = 3
#
# print(b.s)
class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
n=444
class Bar(object):
# n = 333
pass
class Foo(Bar):
# n=222
pass
class Teacher(Foo,metaclass=Mymeta):
# n=111
pass
print(Teacher.n)