2017-05-25 61 views
1

从我所了解的关于Python面向对象的编程中,如果一个类已经定义了__call__方法,如果我们像使用函数调用一样使用类的实例,就会调用该方法。例如:__call__类型的方法

class Employee: 
    def __init__(self,name,sal): 
     self.name = name 
     self.salary = sal 
    def __call__(self,value): 
     return self.salary * value 

e = Employee("Subhayan",20000) 
print (e(10)) 

因此,__call__方法将对象实例作为第一个参数。

我只是想了解Python中的元类,我读到type是所有用户定义的类的默认元类。

如果我定义Python中的基本定制元类:

class Meta(type): 
    def __new__(meta, classname, supers, classdict): 
     # Run by inherited type.__call__ 
     return type.__new__(meta, classname, supers, classdict) 

现在按照书中给出的文档的元类__new__方法将由从类型继承了__call__方法运行。

现在我的问题是使用任何类的__call__方法,我们必须拥有该类的对象,然后将其作为函数调用。

这里我们没有任何类型的对象使用它的__call__函数。

有人可以请我解释一下类型类的__call__函数是如何进入图片的?

回答

0

请记住,type是一个元类,所以它的实例是类,而不是对象。不是方法(除其他事项外),当你做到这一点:

e= Employee(*args,**kwargs) 

要调用Employee.__init__并从元类的一些方法,包括Meta.__call__,同样的道理,当你做。

print (e(10)) 

您正在调用您的自定义__call__方法。

就拿这个Singleton元类:

class Singleton(type): 
    _instances = {} 
    def __call__(cls, *args, **kwargs): 
     if cls not in cls._instances: 
      cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) 
     return cls._instances[cls] 

class MyClass(BaseClass): 
    __metaclass__ = Singleton 

现在每次创建的MyClass一个新的实例时,在元类的__call__方法之前调用创建实际的实例让你检查前一个存在并返回。

希望这会有所帮助。

+0

这里有一个问题。在Singleton __call__函数内部,cls参数将具有MyClass的值。 _instances属于Singleton类。那么MyClass如何拥有_instances字典? –

+0

因为'MyClass'是'Singleton'的一个实例。 – yorodm

+0

Subhayan:...和所有'Singleton'实例共享相同的'_instances'字典,因为它是一个类,_not_不是实例,属性。 – martineau

1

任何类本身都是类型“type”的一个实例 - 因此,“调用”一个类只是调用其类上的方法__call__ - 碰巧类型为__call__。 的type.__call__的效果是完全: 上类似的代码:

class A: 
    pass 
b = A() 
  1. type.__call__接收类A本身作为第一个参数。
  2. 它调用A.__new__ - 以伪代码的形式,我们可以编写instace = A.__new__(cls)作为运行的代码。
  3. ,返回“A”类的一个实例
  4. 然后在实例(instance.__init__()
  5. 调用__init__ ...并返回该实例return instance

但是,如果类本身是从“类型”派生的,即它是“新”类的实例化,需要采取额外的步骤:魔术__class__变量的特殊值填充在任何类方法中 - 如果其中任何一种方法使用了调用到super。在Python 3.6中,还有另外两个步骤:调用定义__set_name__方法的任何类属性,并调用该类的__init_subclass__方法。

+0

我会开一个新的问题,因为当类本身是从类型派生的时候,我还不清楚。我将在那里粘贴一个新的代码,所以请帮助我。 –

+0

另外,直到一个类被创建,它不是一个类型的实例。所以当上面的代码调用A()时,我可以理解被调用类型的__call__方法。但__new__应该在类语句运行时立即调用。但正如你所提到的__new__正在从__call__中调用。不知道我是否理解正确。 –