元类

code='
gloabl 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("jerry","男神")
# # 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 = "oldboy"
# def hello(self):
#     print(self)
# """
#
# exec(code,{},class_namespace)
# print(class_namespace)
从创建类的另一种方式
自己来实例化type类
# obj = type(class_name,class_bases,class_namespace)

 

#限制一个类必须拥有类注释 否则不允许创建类
class MyMeta(type):
    def __init__(self,cls_name,bases,namespace):
        if not self.__doc__:
            raise TypeError('必须包含类注释!!')
        super().__init__(cls_name,bases,namespace)#保证父类代码也走过了
class Animal(metaclass=MyMeta):
    '''
    kjl
    '''
    pass


print(Animal.__doc__)
# print(Animal)

#a继承b 都拥有func

#ORM框架中 要通过检测类的信息来创建表
添加注释例子

 


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(a)
        print(b)
        print(c)
        self.school='xxx'
    pass

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


__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("bgon") # 是为了创建并实例化一个Student类的对象
print(s)

__init__创建类对象的时候执行 控制类的创建过程
__call__实例化产生对象时执行 控制对象的创建过程




单例模式:
一种设计模式,MVVM MVC MTV
常推荐书籍见设计模式

要保证一个类只能有一个实例(单例)
目的是为了节省内存开销
如果两个对象的数据一模一样 就没有必要创建新对象 直接使用已有的即可
场景:当一个类的所有实例数据都完全相同时,则应该设计为实例
音乐播放器类 实例化产生播放器对象
单例的实现方式:
自定义元类 覆盖__call__ 添加判断逻辑 保证只能实例化一个对象
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("我的滑板鞋!")
播放器案例

存在元类时的属性查找:
# 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)


查找顺序:
先自己 在父类 在元类
posted @ 2019-03-22 18:50  777ijBGly-  阅读(206)  评论(0编辑  收藏  举报