从创建类到创建实例的过程深刻理解元类

1. 创建类对象和创建实例对象的过程

class Cat(object):
    # 类属性
    name = '吉姆'
    
    def eat(self):
        print('%s在吃鱼'%self.name)
    
    def drunk(self, name):
        self.name = name
        print('%s在喝水'%self.name)

tumao = Cat()
lanmao = Cat()

这段代码执行过程如下:

在Python中,类本质上也是对象,只不过这个对象拥有创建对象(实例)的能力。

2. 元类

  • 所有类的元类——type类详解

type(类名,父类元组,包含属性的字典(类中的名称和值对)),比如:

1. 构建Foo类
class Foo(object):
    bar = True
# 使用type构建,等同于
Foo = type('Foo', (), {'bar':True})

2. 构建FooChild继承Foo类
class FooChild(Foo):
    pass

def echo_bar(self):
    print self.bar

# 使用type构建FooChild类,并在此类中加入echo_bar方法
FooChild = type('FooChild', (Foo,), {'echo_bar':echo_bar})
  • 自定义元类,从而在创建类的时候能自动改变类

(1)给当前类指定元类的两种方式

1. 第一种方式,通过__metaclass__指定
class Foo(object):
    __metaclass__ = upper_attr

2. 第二种方式
class Foo(object, metaclass=upper_attr):
    pass

 【在类被定义的时候,还没有在内存中生成,直到被调用。Python此时做了如下操作:

   1)检查Foo中是否由__metaclass__属性,如果找到了,就根据此属性创建一个名字为Foo的类对象

   2)如果没有,检查Foo的父类

   3)如果还没有,去模块层次中找

   4)如果还是找不到,就用内建类type创建这个类】

(2)使用第一种方式指定元类时,创建元类的方法

def upper_str(future_class_name, future_class_parents, future_class_attr):
    # 这个元类的功能是:在创建类的时候,保证类中的属性都是大写字母形式的
    attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
    
    # 将这些属性转化成大写字母
    uppercase_str = {name.upper(): value for name, value in attrs}
    
    # 利用新转化的属性构建类
    return type(future_class_name, future_class_parents, uppercase_attr)

class Foo():
    __mataclass__ = upper_str
    bar = 'bip'

(3)使用第二种方式指定元类时,创建元类的方法

# 创建一个类,此类一般以MetaClass结尾,继承自type类
class UpperAttrMetaClass(type):
    # 如果指定元类,会调用类的__new__方法创建类对象
    def __new__(cls, name, bases, attr):
        attrs = ((name, value) for name, value in attr.items())
        
        uppercase_attr = {name.upper: value for name, value in attrs}
        
        return super(UpperAttrMetaClass, cls).__new__(cls, name, bases, uppercase_attr)

class Foo(metaclass=UpperAttrMetaClass):
    pass

 3. 单例模式的实现

  • 什么是单例模式?

单例是一种设计模式,应用该模式的类指挥生成一个实例。保证了在程序的不同位置都可以且仅可以取到同一个对象实例

举个实际例子,说明单例模式的应用场景:

有一款游戏软件,游戏中需要由“场景管理器”来管理游戏场景的切换、资源载入等任务,这个管理器类需要有多种方法和属性,在代码的很多地方都会调用,但不管在什么位置调用此管理器,都需要保证调用的是同一个管理器。

  • 单例模式的四种实现方式
1. 实现方式一:函数装饰器/类装饰器

# 定义装饰器,装饰器修饰类的时候,只执行一次
def singleton(cls):
    # 接收的cls是一个类对象
    _instance = {}
    def inner():
        if cls not in _instance:
            _instance[cls] = cls()
        return _instance[cls]
    
    return inner

@singleton
class Cls(object):
    def __init__(self):
        pass

cls1 = Cls()
cls2 = Cls()
print(id(cls1) == id(cls2))

2. 实现方式二:在__new__方法中干预
class Single():
    _instance = None
    def __new__(cls, *args, **kw):
        if cls._instance is None:
            cls._instance = object.__new__(cls, *args, **kw)
        return cls._instance
    
    def __init__(self):
        pass

3. 实现方式三:元类
class Singleton(type):
    def __init__(self, *args, **kw):
       self._instance = None
    
    def __call__(self, *args, **kw):
        if self._instance is None:
            self._instance = super(Singleton, self).__call__(*args, **kw)
        return self._instance

 

posted @ 2022-04-07 14:34  SmartLiu  阅读(75)  评论(0编辑  收藏  举报