(python) 元类

在了解元类的时候先了解一下储备的知识:


exec 执行储存在字符串或文件中的 Python 语句,相比于 eval,exec可以执行更复杂的 Python 代码。

它的语法是:exec(object,globals,locals)

参数介绍(http://www.runoob.com/python3/python3-func-exec.html)

  • object:必选参数,表示需要被指定的Python代码。它必须是字符串或code对象。如果object是一个字符串,该字符串会先被解析为一组Python语句,然后在执行(除非发生语法错误)。如果object是一个code对象,那么它只是被简单的执行。
  • globals:可选参数,表示全局命名空间(存放全局变量),如果被提供,则必须是一个字典对象。
  • locals:可选参数,表示当前局部命名空间(存放局部变量),如果被提供,可以是任何映射对象。如果该参数被忽略,那么它将会取与globals相同的值。

#代码一
code='''
global x
x=0
y=2
'''
globals_dic={'x':10000}
locals_dic={}
exec(code,globals_dic,locals_dic)
print(globals_dic)
print(locals_dic)
#代码二
code='''
x=1
y=2
def f1(self,a,b):
    pass
'''
locals_dic={}
exec(code,{},locals_dic)
print(locals_dic)

我们平常定义一个类是这样子的。用class定义的类使用的类使用产生我们自己的对象的

class Chinese:
    country='china'
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
    def speak(self):
        print('%s speak Chinese'%self.name)
p=Chinese('MONICX',23,'male')
print(type(p))#<class '__main__.Chinese'>
print(type(Chinese))#<class 'type'>
 
 

元类,就是类的类。

python内置元类type是用来专门产生class定义的类

what:类名,bases:基类,dict:类体代码。

我们来看一下type是如何来定义一个类的。它的代码过程如下。

class_name='Chinese'
class_base=(object,)
class_body='''
country="china"
def __init__(self,name,age,sex):
    self.name=name
    self.age=age
    self.sex=sex
def speak(self):
    print('%s speak Chinese'%self.name)
'''
class_dic={}
print(exec(class_body,{},class_dic))
Chinese=type(class_name,class_base,class_dic)
print(Chinese)

通过上面的代码我们可以了解到内置元类type得到一个类的底层原理。

那么我们如何自定义一个元类呢!!!!!

自定义元类的储备知识:

# __call__
class Foo:
    #产生对象执行
    def __init__(self):
        pass
    #打印对象执行
    def __str__(self):
        pass
    #回收对象执行
    def __del__(self):
        pass
    #调用对象时执行
    def __call__(self, *args, **kwargs):
        print('__cal__')#__cal__ 
        print('__cal__',args,kwargs)#__cal__ (1, 2, 3) {'m': 1}

obj=Foo()
obj(1,2,3,m=1)


内置元类type内部一定有一个__call__方法,我们自定义一个元类的时候,也要定义一个__call__方法。

我们来看一下自定义元类的实现过程。

class Mymeta(type):
    #控制类的创建
    def __init__(self,class_name,class_base,class_dic):
        # print(class_name)#Foo
        # print(class_base)#(<class 'object'>,)
        # print(class_dic)#{'__module__': '__main__', '__qualname__': 'Foo', 'x': 1, '__init__':
                        # <function Foo.__init__ at 0x0000000001E8A950>, 'f1': <function Foo.f1 at 0x0000000001E8A9D8>}
        if not class_name.istitle():
            raise TypeError('类名的首字母必须大写!')

        if not class_dic.get('__doc__'):
            raise TypeError('类中必须写好文档注释,')
    #控制类Foo的调用,即控制实例化Foo的过程
    def __call__(self, *args, **kwargs):#self=Foo args=(111,
        # print('=======>')
        # print(args)
        # print(kwargs)
        #1、造一个Foo的空对象
        obj=object.__new__(self)#固定代码一
        #2、调用Foo.__init__
        #3、将obj连同调用Foo括号内的参数一同传给__init__
        self.__init__(obj,*args,**kwargs)#固定代码二
        return obj
#Foo=Mymeta('Foo',(object),class_dic)
class Foo(object,metaclass=Mymeta):
    '''
    文档注释
    '''
    x=1

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

    def f1(self):
        print('form f1')

# obj=Foo()#调用类会产生一个空对象。
# print(obj)

obj=Foo(1111)#Foo.__call__()
print(obj.y)
print(obj.f1)
print(obj.x)


猜你喜欢

转载自blog.csdn.net/miaoqinian/article/details/79971579
今日推荐