元类
元类的定义
实例化一个类,产生对象。
在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}