day24-1 元类

元类

在python中一切皆对象,name我们用class关键字定义的类本身也是一个对象,负责产生该对象的类称之为元类,即元类可以简称为类的类

元类是负责产生类的,所以我们学习元类或者定义元类的目的是:为了控制类的产生过程,还可以控制对象的产生过程

类的组成

class People(object):
    x = 1
    print('from people')
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def speak(self):
        print('from speak')

在用class关键字定义类时,在定义阶段会执行类体中的代码,创建名称空间,所以类由三部分组成

  • 类名class_name:People
  • 基类class_bases:(object,)
  • 类的名称空间class_dic

内置函数 exec()

将字符串中的代码执行,然后把产生的全局名称丢入到global_space字典中,局部名称丢入到local_space字典中

cmd = """
x = 1
global y
y = 10
def __init__(self, name, age):
    self.name = name
    self.age = age

def speak(self):
    print('from speak')
""" 
global_space = {}
local_space = {}
exec(cmd,global_space,local_space)  # 未声明gloabal的变量全是局部变量
print('local:',local_space)
local: {'x': 1, '__init__': <function __init__ at 0x000002C2319EB158>, 'speak': <function speak at 0x000002C2319EB0D0>}

class关键字创建类原理

用class关键字创建一个类,用的默认的元类type

class_name = 'P'  # 类名
class_bases = (object,)  # 基类
cmd = """
x = 1
global y
y = 10
def __init__(self, name, age):
    self.name = name
    self.age = age

def speak(self):
    print('from speak')
""" 
global_space = {}
local_space = {}
exec(cmd,global_space,local_space)
class_dic = local_space  # 类的名称空间

P= type(class_name, class_bases, class_dic)
print(P)
<class '__main__.P'>

自定义元类控制类的创建

  • 控制创建类时必须写说明,没写就抛出异常
class Mymeta(type):
    def __init__(self, class_name, class_bases, class_dict):
        if not class_dict.get('__doc__'):
            raise TypeError('必须写说明')
        super(Mymeta, self).__init__(class_name, class_bases, class_dict)


class People(object, metaclass=Mymeta):
    """
    SJFDSFSD
    """
    country = 'Chinese'

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

    def test(self):
        print('from f1')
  • 控制创建类时类名不能全为小写,类名全为小写则抛出异常
class Mymeta(type):
    def __init__(self, class_name, class_bases, class_dict):
        if class_name.islower():
            raise TypeError('类名不能全为小写')
        super(Mymeta, self).__init__(class_name, class_bases, class_dict)


class People(object, metaclass=Mymeta):
    country = 'Chinese'

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

    def test(self):
        print('from f1')

自定义元类控制类实例化

类的实例化就是元类的调用,类实例化原理:

  • 先造出一个空对象
  • 为该空对象初始化独有的属性
  • 返回一个初始化好的对象
class Mymeta(type):
    def __init__(self, class_name, class_bases, class_dict):
        super(Mymeta, self).__init__(class_name, class_bases, class_dict)

    # 控制类Foo的调用过程,即控制实例化Foo的过程
    def __call__(self, *args, **kwargs):

        # 造一个空对象obj
        obj = object.__new__(self)

        # 调用Foo.__init__,将obj连同调用Foo括号内的参数一同传给__init__
        self.__init__(obj, *args, **kwargs)
        return obj


class Foo(object, metaclass=Mymeta):
    x = 10

    def __init__(self, y):
        self.y = y


f = Foo(1)
print(f.__dict__)
{'y': 1}

自定义元类后对象属性查找顺序

对象本身-->类-->父类-->父类-->object-->type找不到报错

原文地址:https://www.cnblogs.com/863652104kai/p/11083661.html