类的补充:元类、元类创建过程、单例、元类实现单例

本文目录:

一、元类

二、通过元类来控制类的创建过程

三、控制类的调用(实例化)

四、单例模式

五、元类实现单例

 

 

一、元类

元类是什么?

本质上也是一个类,元类是用于实例化其他类,对象怎么来的是类实例化出来的,那类这个对象怎么来的呢?就是由元类实例化出来的。因为在在python中一切皆对象。

# class Person:
#     pass

# 类也是对象 在使用上与函数对象没啥区别
# obj = Person
# li = [Person]
#
# def func(cls):
#     print(cls)
# func(Person)

class Dog:
    def __init__(self):
        print('狗的初始化了')
    color = 'red'

    def talk(self):
        print('狗叫了')

d1 = Dog()
print(Dog.__dict__)
# 查看对象是哪个类实例化出来的
print(d1.__class__)
print(Dog.__class__)
print(type(d1))
print(type(Dog))
# 一个类必须具备的内容 """ 1.类名 2.基类 3.名称空间 """ # 通过查看__class__发现Dog对象是有type类实例化出来的 # 既然如此,是不是可以手动调用type来实例化 class_name = "Pig" bases = (object) pic_dict = {} class_body = """ def __init__(self): print("猪的初始化") color = "red" def talk(self): print("猪在叫") """ # 执行一堆字符串代码 将生产的内容放到pic_dict中 exec(class_body,{},pic_dict) print(pic_dict) # 调用type产生一个类 c = type(class_name,bases,pic_dict) print(c) print(Dog) """ 默认情况下 所有的类都是通过type这个元类实例化的 我们完全可以自己实例化 元类的作用 用于创建类的类 成为元类 """

 

二、通过元类来控制类的创建过程

class MyMetaclass(type):
    # 什么时候执行?  MyMetaclass 定义一个类是 系统会自动去调用元类
    def __init__(cls,class_name,bases,namespace):
        # 既然创建类时 会自动执行 该方法 那完全可以编写一些逻辑在init中 来控制类的创建
        # 首字母必须大写否则不让创建
        if not class_name.istitle():
            raise TypeError("类名首字母必须大写!")

        if object not in bases:
            raise TypeError("必须显式的继承object")

        print(cls)
        print(class_name)
        print(bases)
        print(namespace)
# 当求解释器执行到这行diamante时  自动调用了MyMetaclass
# class Foo(metaclass=MyMetaclass): # 等同于 Foo = MyMetaclass()
#     attr = 123
#     pass
class Foo1(object,metaclass=MyMetaclass): # 等同于 Foo = MyMetaclass()
    attr = 123
    pass

 

三、控制类的调用(实例化)

class Bar:
    def __call__(self,*args,**kwargs):
        print("run call")

# 调用类时 还是调用对象时执行
b1 = Bar()

b1()
print(b1)
# 在调用对象时,自动触发了__call__的执行
# 推到b1是Bar的实例,调用b1会触发bar中的__call__
# Bar是Type的实例,调用Bar应当触发type中的__call__

class MyMetaClass(type):

    def __call__(self, *args, **kwargs):
        print("MyMetaClass __call__ run!")
        print(self)

        # 需求判断实例化时的参数必须是字符串类型
        if type(args[0])!= str:
            raise TypeError('名字必须是字符串类型!')
        # 这是自定义元类时,必须要有的模板,以保证可以正常实例化产生对象
        obj = object.__new__(self)
        obj.__init__(*args,**kwargs)
        return obj

class Foo(metaclass=MyMetaClass):
    def __init__(self,name):
        self.name = name
    pass

# 调用类本质上就是调用__call__ 其返回值表示实例化得到的对象
res = Foo('bbb')
print(res)
# 调用一个类,创建出一个空对象,调用__init__来完成对象的初始化,返回该对象
# 控制类的调用,也就是实例化过程,核心函数元类中的__call__
# 需要注意的是,在__call__中应当先完成基础的逻辑1.创建空对象 2.执行__init__ 3.返回新对象
# 在此基础上添加新的业务逻辑

 

四、单例模式

"""

    单例
        是一种设计模式
        是设计模式中比较简单的
        指的是 一个类有且仅有一个实例 就叫单例

    实现单例 就通过判断是否已经创建过对象

    为什么要使用单例这种模式
    之前在创建对象时 每个对象中的数据不相同   对象实际上数据和处理数据的方法的结合体
    当对象中的数据是 相同的 共享的 时候 使用单例


    u1 = user("张三",29,"man")
    u2 = user("张三",29,"man")
    u3 = user("张三",29,"man")
    不同的对象 有完全相同的数据  没有必要每个人保存一份

    u1 = user("张三",29,"man")
    u2 = u1
    u3 = u1
    如此  可以减少资源开销  大家共享一个数据 只有一个对象


"""

class User:

    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

    instance = None
    # 通过指定的方法来获取实例 而不是调用类来创建新对象
    @classmethod
    def get_instance(cls,name,age,sex):
        if not cls.instance:
            cls.instance = cls(name,age,sex)
        return cls.instance

    @staticmethod
    def get_instance2(name,age,sex):
        if not User.instance:
            User.instance = User(name,age,sex)
        return User.instance

# u1 = User("张三",20,"man")
# u2 = User("张三",20,"man")



u1 = User.get_instance2("张三",20,"man")
print(u1)
u2 = User.get_instance2("张三",20,"man")
print(u2)


# 通过classMethod 可以完成单例  但是还是可以通过直接调用;类产生新对象  此时就需要用到元类
u3 = User("张三",20,"man")

 

五、元类实现单例

class MyMetaClass(type):

    instance = None
    def __call__(cls, *args, **kwargs):
        if not MyMetaClass.instance:
            # 创建空对象
            MyMetaClass.instance = object.__new__(cls)
            print("创建新的播放器对象!")
            #初始化对象
            MyMetaClass.instance.__init__(*args,**kwargs)
            # 返回对象
        return MyMetaClass.instance

# 只能有一个播放器实例
class CDPlayer(metaclass=MyMetaClass):
    def play(self,music):
        print("切换音乐",music)
    def __init__(self,music_name):
        self.music_name = music_name

p1 = CDPlayer("你发如雪!")
p1.play("菊花台")
p1.play("菊花台2")
p1.play("菊花台3")

# 不会创建新对象
p1 = CDPlayer("你发如雪!")
p1 = CDPlayer("你发如雪!")
p1 = CDPlayer("你发如雪!")
p1 = CDPlayer("你发如雪!")

# 元类实现单例 就是拦截了元类中的__call__的正常执行  使得创建对象都必须经过自己判断逻辑




# 类中的__init__也被拦截了

 

资料参考:

https://www.jianshu.com/p/c1ca0b9c777d(python元类)

posted @ 2019-01-15 18:19  仗剑煮大虾  阅读(183)  评论(0编辑  收藏  举报