python__init__和__call__

Posted 浮云向晚

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python__init__和__call__相关的知识,希望对你有一定的参考价值。

__init____call__都是Python中的特殊方法(也称为魔术方法),它们都与类的实例化有关。

__init__是一个构造函数,用于初始化类的实例。当创建一个新的类实例时,Python会自动调用__init__方法。在__init__方法中,我们可以设置对象的属性和执行其他必要的初始化操作。

__call__方法允许我们将一个类实例像函数一样进行调用。当我们调用一个类实例时,Python会自动调用__call__方法。在__call__方法中,我们可以定义类实例的行为,就像定义一个函数一样。

下面是一个例子,展示了如何使用__init____call__方法:

class MyClass:
    def __init__(self, x):
        self.x = x
    
    def __call__(self, y):
        return self.x + y

obj = MyClass(10)
result = obj(5)
print(result) # Output: 15

在上面的例子中,我们定义了一个名为MyClass的类,并在__init__方法中初始化了一个属性x。在__call__方法中,我们定义了一个行为,它将x和传递给类实例的参数y相加,并返回结果。我们创建了一个名为obj的类实例,并将其初始化为MyClass(10)。然后,我们将obj作为函数进行调用,传递参数5,并将结果存储在result变量中。最后,我们打印result的值,它应该是15

原创Python 对象创建过程中元类, __new__, __call__, __init__ 的处理

原始type:

type是最原始的元类,其__call__方法是在你使用" t_class = type(classname_string, base_classes_tuple, attributes_dict)" 这种语法来使用时, 在__call__方法内使用又会调用type的__new__和__init__方法来创建classname_string的具体类,并初始化类信息。当type(***)调用完成, classname_string代表的类可以用来创建实例了。

 

 

元类调用过程: 原始type元类同理

如下流程:假设是MyMeta元类,而不是原始type元类

例子: MyClass = MyMeta(‘MyClass‘, bases, attributes)

 

my_meta_type = type(MyMeta)MyClass= my_meta_type.__call__(MyMeta, cls, bases, attributes)
在__call__中应该是如下操作:
MyClass = MyMeta.__new__(MyMeta, cls, bases, attributes) meta_class = MyClass.__metaclass__ meta_class.__init__(MyClass, cls, bases, attributes) return MyClass

最终返回MyClass类

 

上述元类有一个很令人迷惑的地方,需要注意到,当你的元类是自定义的元类的时候,假设是MyMeta,此时调用的是MyMeta的父元类type的__call__,所以假设MyMeta自定义了__call__,你要知道当调用MyMeta()的时候,该函数并没有被调用,调用的是type的__call__,你定义MyClass对象实例时才会调用该函数。

总结: 元类处理过程:定义一个类时,使用声明或者默认的元类对该类进行创建,对元类求type运算,得到父元类(该类声明的元类的父元类),调用父元类的__call__函数,在父元类的__call__函数中, 调用该类声明的元类的__new__函数来创建对象(该函数需要返回一个对象(指类)实例),然后再调用该元类的__init__初始化该对象(此处对象是指类,因为是元类创建的对象),最终返回该类。

 

你可以简单实验以下,自定义俩个元类,该俩个元类是父子关系,在定义一个类,设置使用自定义元类的子元类,发现会调用自定义元类的父元类中call的输出,子元类的call并没有输出,在定义类的对象时才输出了

例子如下:

class SuperMeta(type):

    def __call__(metaname, clsname, baseclasses, attrs):

        print ‘SuperMeta Called‘

        clsob = type.__new__(metaname, clsname, baseclasses, attrs)

        type.__init__(clsob, clsname, baseclasses, attrs)

        return clsob

 

 

class MyMeta(type):

    __metaclass__ = SuperMeta

    def __call__(cls, *args, **kwargs):

        print ‘MyMeta called‘, cls, args, kwargs

        ob = object.__new__(cls, *args)

        ob.__init__(*args)

        return ob

 

print ‘create class‘

 

class Kls(object):

    __metaclass__ = MyMeta

 

    def __init__(self, data):

        self.data = data

 

    def printd(self):

        print self.data

 

print ‘class created ---------------------‘

# 你会发现定义了 Kls 类后输出了 SuperMeta 父元类的输出

ik = Kls(‘arun‘)

ik.printd()

ik2 = Kls(‘avni‘)

 

ik2.printd()

# 定义Kls对象实例才真的执行了MyMeta的call

 

为什么type会调用自己的呢,因为type的type还是type, 蛋疼一小会……

 

附加:

原始type的__call__应该是参数结构应该是:

  metaname, clsname, baseclasses, attrs

 

原始type的__new__

  metaname, clsname, baseclasses, attrs

 

原始type的__init__

  class_obj, clsname, baseclasses, attrs

 

元类的__new__和__init__影响的是创建类对象的行为,父元类的__call__控制对子元类的 __new__,__init__的调用,就是说控制类对象的创建和初始化。父元类的__new__和__init__由更上层的控制,

    一般来说,原始type是最初的父元类,其__new__和__init__是具有普遍意义的,即应该是分配内存、初始化相关信息等

元类__call__影响的是创建类的实例对象的行为,此时如果类自定义了__new__和__init__就可以控制类的对象实例的创建和初始化

 

 

参考:

http://pythoncentral.io/how-metaclasses-work-technically-in-python-2-and-3/

http://stackoverflow.com/questions/2608708/what-is-the-difference-between-type-and-type-new-in-python  Florentin的答案

 

classKls(object):
    __metaclass__=MyMeta
 
    def__init__(self,data):
        self.data=data
 
    defprintd(self):
        printself.data
 




以上是关于python__init__和__call__的主要内容,如果未能解决你的问题,请参考以下文章

[python][转载]__init__.py使用

在 Python 和 __init__.py 中导入模块

[Python] 关于__init__.py

python包中__init__.py的作用

Python __init__.py 作用详解

Python __init__.py 作用详解