元类

元类的定义

实例化一个类,产生对象。
在python中,类是怎么产生的?

实例化一个元类,得到一个类。

元类---实例化---->类(People)---实例化---->对象(obj)

python强调一切皆对象。元类就是最初的类,它可以产生别的类,别的类在产生对象。

调用类的__class__方法:得到元类type

属性的查找顺序:
属性查找:对象本身,类,父类,,,父类不是元类
以对象为起始找,找不到元类里去,
以类为起始找,能找的到元类

元类实例化产生的就是类,class语法,就是对元类的实例化,产生一个类。
类的三大特征:类名、类的基类、执行类体代码,拿到类的名称空间
这是两种相同的意思:
class People
People = type(类名,类的基类,名称空间)
People是对元类type的实例化。

产生类的过程:
实例化类发生的事:(类也是对象)

产生一个空对象,调用__new__方法,返回空对象,和参数给__init__方法;
有了空对象,调用type的__init__方法,初始化对象;
返回对象

所有的步骤,肯定会有一段代码来控制,这个方法是__call__,当对象被调用时执行

当我们调用一个整数类型的时候,会报错,不可调用。
当我们调用一个函数的的时候,它是可以调用的。

所以,决定一个变量可不可以被调用,是看它是什么类型。
所以,__call__方法,被定义在类里,当生成的对象被调用的时候,它就被触发了。
对象是一个具体的,类是抽象的,包含各种属性,数据属性,方法属性,还有一些内置方法,比如,__call__,当满足一定条件的时候,就触发执行。

len :__len__
'abc':__str__ :打印时,触发   return 值,被打印
__init__ :实例化对象时,触发
__del__ :删除,清理对象时,触发,程序结束,也是这个情况,将对象清理了
当程序调用了系统的资源,可以程序结束的时候,帮系统释放

重点:
首先,通常对象是不可以被调用的,为什么:因为对象所属的类中没有__call__方法,所以不可以被调用。
而,产生对象,将类进行实例化,people = People('egon',20),这是调用类People,返回一个对象people。
所以,类是可以被调用的,所以,类所属的类中,是有__call__方法的。

即,元类中有__call__方法,普通的类是没有__call__方法的。(当然你也可以加,这样对象也可以被调用,我们讨论的是正常的情况)

当,实例化类产生对象的时候,也就是 类 被调用了,这样就会触发 元类 中的__call__方法的执行。即,元类中的__call__方法执行

当类被调用,也就是实例化类产生对象,元类中__call__方法执行,类在实例化产生对象的过程,这个过程,就是__call__方法执行的过程。
即,产生空对象,初始化对象,返回对象。
产生空对象是__new__方法,完成的;然后,在将空对象self,和参数,传入__init__方法将对象进行初始化;最后返回一个对象。

__new__ :早于__init__执行,
def __new__(cls,*args,**kwargs):
    cls :这个类本身
    args:元组:对象名,对象基类,对象名称空间(对象好像没有这些,,,毕竟是新产生的,然后,继承是类所具有的)

自定义元类:Mymeta

class People(metaclass=Mymeta):
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say(self):
        print('%s:%s' %(self.name,self.name))

    def __new__(cls, *args, **kwargs):
        # 产生真正的对象,注意这个是object类的继承
        return object.__new__(cls)

# 类的调用
# obj=People('egon',18) =》Mymeta.__call__=》干了3件事
# 1、Mymeta.__call__函数内会先调用People内的__new__
# 2、Mymeta.__call__函数内会调用People内的__init__
# 3、Mymeta.__call__函数内会返回一个初始化好的对象

通常的类的定义中,没有__new__方法:
<built-in method __new__ of type object at 0x000000001D8131C0>
这是一个元类的内置方法,注意:类是元类的实例化。所以,类中没有,去元类找。
raise NameError('...')  抛出异常(这只是个语法)

自定义元类:元类是type,我们可以自定义一个元类,在原来的基础上,加一些功能或逻辑。Mymeta是一个自定义的元类。meta元类的意思。
一个类没有声明自己的元类,默认他的元类就是type,除了使用内置元类type,我们也可以通过继承type来自定义元类,然后使用metaclass关键字参数为一个类指定元类

class Mymeta(type): # 只有继承了type类的类才是元类
    def __call__(self, *args, **kwargs):
        # 1、Mymeta.__call__函数内会先调用People内的__new__
        people_obj=self.__new__(self)
        # 2、Mymeta.__call__函数内会调用People内的__init__
        self.__init__(people_obj,*args, **kwargs)

        # print('people对象的属性:',people_obj.__dict__)
        people_obj.__dict__['xxxxx']=11111
        # 3、Mymeta.__call__函数内会返回一个初始化好的对象
        return people_obj

产生类StanfordTeacher的过程就是在调用Mymeta,而Mymeta也是type类的一个对象,那么Mymeta之所以可以调用,一定是在元类type中有一个__call__方法
# 类的产生
# People=Mymeta()=》type.__call__=>干了3件事
# 1、type.__call__函数内会先调用Mymeta内的__new__
# 2、type.__call__函数内会调用Mymeta内的__init__
# 3、type.__call__函数内会返回一个初始化好的对象


补充:exec的用法

#exec:三个参数

#参数一:包含一系列python代码的字符串

#参数二:全局作用域(字典形式),如果不指定,默认为globals()

#参数三:局部作用域(字典形式),如果不指定,默认为locals()

#可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中
g={
    'x':1,
    'y':2
}
l={}

exec('''
global x,z
x=100
z=200

m=300
''',g,l)

print(g) #{'x': 100, 'y': 2,'z':200,......}
print(l) #{'m': 300}
原文地址:https://www.cnblogs.com/pythonwl/p/12707070.html