metaclass,__call__,__new__,__init__

重点分清楚对象是由A类实例化的,A类是由B类实例化的,

调用B类的__call__(self,*args,**kwargs),self=A

__call__()函数中执行

A_obj=self.__new__(self),

self.__init__(A_obj,*args,**kwargs)

return A_obj


示例一: 

示例一:
class Mymeta(type):
    def __init__(self,name,bases,dic):
        print('===>Mymeta.__init__')


    def __new__(cls, *args, **kwargs):
        print('===>Mymeta.__new__')
        return type.__new__(cls,*args,**kwargs)

    def __call__(self, *args, **kwargs):          #若Foo('eagon'),self 为Foo,*args='egon'
        print('aaa')
        obj=self.__new__(self)
        self.__init__(self,*args,**kwargs)
        return obj

class Foo(object,metaclass=Mymeta):
    def __init__(self,name):
        self.name=name
    def __new__(cls, *args, **kwargs):
        return object.__new__(cls)

'''
需要记住一点:名字加括号的本质(即,任何name()的形式),都是先找到name的爹,然后执行:爹.__call__  
而爹.__call__一般做两件事:
1.调用name.__new__方法并返回一个对象
2.进而调用name.__init__方法对儿子name进行初始化
'''

'''
class 定义Foo,并指定元类为Mymeta,这就相当于要用Mymeta创建一个新的对象Foo,于是相当于执行
Foo=Mymeta('foo',(...),{...})
因此我们可以看到,只定义class就会有如下执行效果
===>Mymeta.__new__
===>Mymeta.__init__
实际上class Foo(metaclass=Mymeta)是触发了Foo=Mymeta('Foo',(...),{...})操作,
遇到了名字加括号的形式,即Mymeta(...),于是就去找Mymeta的爹type,然后执行type.__call__(...)方法
于是触发Mymeta.__new__方法得到一个具体的对象,然后触发Mymeta.__init__方法对对象进行初始化
'''

'''
obj=Foo('egon')
的原理同上
'''

'''
总结:元类的难点在于执行顺序很绕,其实我们只需要记住两点就可以了
1.谁后面跟括号,就从谁的爹中找__call__方法执行
type->Mymeta->Foo->obj
Mymeta()触发type.__call__
Foo()触发Mymeta.__call__
obj()触发Foo.__call__
2.__call__内按先后顺序依次调用儿子的__new__和__init__方法
'''
View Code

示例二:

'''
class Mymeta(type): #但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
    pass

class Teacher(object): #Teacher=Mymeta('Teacher',(object,),{...})
    school = 'Qinghua'

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

    def score(self):
        print('%s is scoring' %self.name)

    def __call__(self, *args, **kwargs):
        print(self)
        print(args)
        print(kwargs)
tea1=Teacher('egon',18,'male')

tea1(1,2,a=1,b=2) #__call__(tea1,(1,2).{'a':1,'b':2})
'''

总结:对象之所以可以调用,是因为对象的类中有一个函数__call__

推导:如果一切皆对象,那么Teacher也是一个对象,该对象之所可以调用,肯定是这个对象的类中也定义了一个函数__call__

class Mymeta(type): #但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
    def __call__(self, *args, **kwargs): #self=Teacher这个类,args=('egon',18,'male'),kwargs={}
        # 1. 先产生一个空对象
        tea_obj=self.__new__(self) #tea_obj是Teacher这个类的对象   self--->Teacher
        # 2. 执行__init__方法,完成对象的初始属性操作
        self.__init__(tea_obj,*args,**kwargs)
        # 3. 返回初始化好的那个对象
        return tea_obj

class Teacher(object,metaclass=Mymeta): #Teacher=Mymeta('Teacher',(object,),{...})
    school = 'Qinghua'
    
    #tea_obj,'egon',18,'male'
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def score(self):
        print('%s is scoring' %self.name)

tea1=Teacher('egon',18,'male') # 会触发Teacher的类(即元类)中的__call__函数
print(tea1)
print(tea1.__dict__)
View Code
原文地址:https://www.cnblogs.com/wddxx/p/13663975.html