面向对象之元类,单例

元类

1 什么是元类:

源自一句话:在python中,一切皆对象,而对象都是由类实例化得到的
class OldboyTeacher:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def score(self):
    print('%s is scoring' %self.name)
    
# tea1=OldboyTeacher('egon',18,'male')
# # print(type(tea1))
# print(type(OldboyTeacher))

# 对象tea1是调用OldboyTeacher类得到的,如果说一切皆对象,那么OldboyTeacher也是一个对象,只要是对象
# 都是调用一个类实例化得到的,即OldboyTeacher=元类(...),内置的元类是type

 

2.关系:

1. 调用元类---->自定义的类
2. 调用自定义的类---->自定义的对象

3.创建自定义类

自定义类的三个关键组成部分:

1. 类名
2. 类的基类们
3. 类的名称空间
class关键字创建自定义类的底层的工作原理,分为四步
1. 先拿到类名:'OldboyTeacher'
2. 再拿到类的基类们:(object,)
3. 然后拿到类的名称空间???(执行类体代码,将产生的名字放到类的名称空间也就是一个字典里,补充exec)
4. 调用元类实例化得到自定义的类: OldboyTeacher=type('OldboyTeacher',(object,),{...})
不依赖class关键字创建一个自定义类
# 1. 拿到类名
class_name='OldboyTeacher'
#2. 拿到类的基类们:(object,)
class_bases=(object,)
#3. 拿到类的名称空间
class_dic={}
class_body="""
school = 'Oldboy'

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

def score(self):
    print('%s is scoring' %self.name)
"""
exec(class_body,{},class_dic)
print(class_dic)

4. 调用type得到自定义的类

OldboyTeacher=type(class_name,class_bases,class_dic)

print(OldboyTeacher)
# print(OldboyTeacher.school)
# print(OldboyTeacher.score)

tea1=OldboyTeacher('egon',18,'male')
print(tea1.__dict__)

 

5.模板

class Mymeta(type): #但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
     def __init__(self,class_name,class_bases,class_dic):
         print(self)
         print(class_name)
         print(class_bases)
         print(class_dic)

class OldboyTeacher(object,metaclass=Mymeta): OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
     school = 'Oldboy'

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

     def score(self):
         print('%s is scoring' %self.name)
控制类的产生
1.类名必须用驼峰体
2.类体必须有文档注释,且文档注释不能为空
总结:对象之所以可以调用,是因为对象的类中有一个函数__call__
推导:如果一切皆对象,那么OldboyTeacher也是一个对象,该对象之所可以调用,肯定是这个对象的类中也定义了一个函数__call__

 

二、单例模式

1.什么是单例

单例:一个类只能产生一个实例

2. 为什么要有单例:

1.该类需要对象的产生
2.对象一旦产生,在任何位置再实例化对象,只能得到第一次实例化出来的对象

3.实现单例的方法:

 方式一:模块
class Songs():
    pass

 s1 = Songs()
 s2 = Songs()
 print(s1, s2)

 对外提供的对象
song = Songs()
 方式二:类方法
class Songs():
    __instance = None
    @classmethod
    def getInstance(cls):
        # 对象没有创建返回,有直接返回
        if cls.__instance == None:
            cls.__instance = cls()
        return cls.__instance


 约定别用 类名() 来实例化对象,用类方法来获取唯一对象
 s1 = Songs()
 s2 = Songs()
 print(s1, s2)

s1 = Songs.getInstance()
s2 = Songs.getInstance()
print(s1, s2)
 方式三:基于__new__
class Songs:
    __instance = None
    def __new__(cls, song_name, *args, **kwargs):
        if cls.__instance == None:
            cls.__instance = object.__new__(cls)
            cls.__instance.song_name = song_name
        return cls.__instance

    def change_song(self, song_name):
        self.song_name = song_name

s1 = Songs('菊花爆满山')
s2 = Songs('感觉身体被掏空')
print(s1.song_name, s2.song_name)  # 菊花爆满山  菊花爆满山
s2.change_song('感觉身体被掏空')
print(s1.song_name, s2.song_name)  # 感觉身体被掏空 感觉身体被掏空
 方式四: 装饰器装饰类
def outer(cls):
    _instance = None
    def inner(*args, **kwargs):
        nonlocal _instance
        if _instance == None:
            _instance = cls(*args, **kwargs)
        return _instance
    return inner

@outer  # Songs = outer(Songs)
class Songs:
    pass


s1 = Songs()
s2 = Songs()
print(s1, s2)
 方式五: 元类实现
class SingleMeta(type):
    __instance = None
    def __call__(cls, *args, **kwargs):
        if SingleMeta.__instance == None:
            SingleMeta.__instance = object.__new__(cls)
            cls.__init__(SingleMeta.__instance, *args, **kwargs)
        return SingleMeta.__instance


class Songs(metaclass=SingleMeta):
    def __init__(self):
        pass
    pass


s1 = Songs()
s2 = Songs()
print(s1, s2)

 __init__,__new__,__call__的区别

 
posted @ 2019-05-05 21:33  为此努力  阅读(158)  评论(0编辑  收藏  举报