__call__ 类型类的方法

use*_*151 5 python metaclass

根据我对 Python 面向对象编程的理解,如果一个类__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))
Run Code Online (Sandbox Code Playgroud)

因此该__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)
Run Code Online (Sandbox Code Playgroud)

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

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

这里我们没有任何类型的对象来使用它的__call__功能。

有人可以向我解释一下__call__type class的功能是如何出现的吗?

jsb*_*eno 5

任何类本身都是“type”类型的实例——因此“调用”一个类只是调用__call__它的类上的方法——这恰好是类型的__call__. 的效果type.__call__正是:在代码上,如:

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

但是,如果类本身是从“类型”派生的——即,它是“新”类的实例化,则需要采取额外的步骤:__class__在任何类方法中填充魔法变量的特殊值——如果有的话这些方法中的一个使用调用super. 在 Python 3.6 上,还有以下 2 个步骤:__set_name__调用定义方法的任何类属性 ,然后调用类的__init_subclass__方法。


yor*_*odm 2

请记住,type是一个元类,因此它的实例是类,而不是对象。比意味着(除其他外)当你这样做时:

e= Employee(*args,**kwargs)
Run Code Online (Sandbox Code Playgroud)

您正在Employee.__init__调用元类中的一些方法,包括Meta.__call__,与您调用时的方式相同。

print (e(10))
Run Code Online (Sandbox Code Playgroud)

您正在调用您的自定义__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
Run Code Online (Sandbox Code Playgroud)

现在,每次创建 的新实例时MyClass,都会在创建实际实例之前__call__调用元类中的方法,从而允许您检查前一个实例是否存在并返回该实例。

希望这可以帮助。