如果 class 没有参数,参数如何传递给 class?

How can the arguments get passed to the class if the class has no parameters?

我可能缺乏非常基本的 python 基础。我正在处理别人制作的脚本。

我有一个脚本,比如说My_Class,其中的代码是:

import thing1
import thing_2
...etc

class My_Class:

    def __init__(self, arg1, arg2 ...etc):
        self.argument_1 = arg1
        self.argument_2 = arg2
        ...etc

my_class 有 __init__ 的参数没有作为参数传递给 my_class 是否正确? (my_class 根本没有参数)

如果 class 没有参数,如何将参数 arg1, arg2 ...etc 传递给 my_class

不应该吗

import thing1
import thing_2
...etc

class My_Class(arg1, arg2 ...etc):

    def __init__(self, arg1, arg2 ...etc):
        self.argument_1 = arg1
        self.argument_2 = arg2
        ...etc

代替?

注:

class 没有被实例化,只调用它的方法,直接在 class 上,即:

My_Class(arg1, arg2 ...etc).method_1()

你的第一个片段是正确的:

class My_Class:

    def __init__(self, arg1, arg2 ...etc):
        self.argument_1 = arg1
        self.argument_2 = arg2
        ...etc

#Instantiation
c = My_Class(arg1, arg2 ...etc)
#Call method on instance
c.method_1()

你肯定实例化class:My_Class(arg1, arg2 ...etc)被python解释为:

  1. 实例化对象。
  2. 对该对象调用 __init__()(在您的情况下使用 arg1、arg2 等)

python 中,__init__() 方法被认为与其他语言中使用的术语 'constructor' 同义。

另请注意,在我上面的代码片段中,变量 c 挂在实例上,这与您的代码片段不同。

我希望这些信息能让您更好地理解为什么我们可以调用我们的 classes,这些参数去哪里,class 的参数在哪里等等

那么,让我们谈谈 __call__ :

考虑在 class 中实现 __call__。它使 class 的实例可以调用,换句话说,“这”是您可以将 () 放在实例之后的原因吗?当您以这种方式调用您的实例时,__call__ 是被调用的实际方法!如果您在 __call__ 方法中将参数定义为参数,则可以在调用实例时传递参数。

class A:
    def __call__(self, arg):
        print('It is calling', arg)

instance = A()
instance('foo')

现在我们知道 classes 本身是 type:

类型的实例 -->
class A:
    pass

print(isinstance(A, type))  # True

所以“他们的”class(最好说 metaclass)中必须有一个 __call__ 方法,当然type 中有一个。这就是我们可以在 class 之后放置 () 来调用它并向其传递参数的原因。

当你把括号放在class前面时,你实际上是在调用classtype的这个__call__方法[=25] =], arg2 ...

等等,但是 __init__ 在哪里? __new__ 在哪里? 他们 是如何接到电话的?

事实上,它们在 class type__call__ 方法中使用您传递的那些参数被调用。首先 __new__ , if it returns an instance of the class then __init__ gets called like a normal instance method.

现在我将演示我之前解释的内容:(所有 classes 的默认元 class 是 type class,但我'我要用我的给你看细节)

class Mymeta(type):
    def __call__(cls, *args, **kwargs):
        print(f"Metaclass's __call__ gets called with: {args} and {kwargs}")
        new_created_instance = cls.__new__(cls, *args, **kwargs)
        if isinstance(new_created_instance, cls):
            new_created_instance.__init__(*args, **kwargs)

        return new_created_instance


class A(metaclass=Mymeta):
    def __new__(cls, *args, **kwargs):
        # return 10    # <-- If you uncomment this, __init__ won't get called.
        return super(A, cls).__new__(cls)

    def __init__(self, name, **kwargs):
        print(
            'This is printed only because'
            ' we called it inside `__call__` method of the meta class'
        )
        self.name = name


obj = A('soroush', age=5)

输出:

Metaclass's __call__ gets called with: ('soroush',) and {'age': 5}
This is printed only because we called it inside `__call__` method of the meta class

注意两件事,首先,我们在 class 前面传递的所有参数都直接传递给 metaclass 的 __call__ 方法。其次,如您所见,Mymeta__call____new____init__ 的调用者。

TLDR:class 的“签名”由其 __init__ and/or __new__ 方法定义。


class 语句是对 metaclass* 的隐式调用。 class 语句的任何参数,包括基数,都由 metaclass 使用。 metaclass 负责使用 class 名称、参数和正文来创建实际的 class 对象。

#              v arguments passed to the metaclass
class My_Class(arg1, arg2, ...):
    ...

值得注意的是,这些是 传递给 元 class 的参数。在常见情况下,这些只是基础 classes;只有高级案例才需要传递甚至期望其他参数。

当调用 class 时,如 My_Class(arg1, arg2, ...),这会将参数传递给 class' __init__ and/or __new__。因此,__init__/__new__ 定义“a class”采用哪些参数

class My_Class:
#                      v parameters taken by the class
    def __init__(self, arg1, arg2 ...etc):
        self.argument_1 = arg1
        self.argument_2 = arg2

*这是对 metaclasses 工作方式的稍微简化。了解大局不需要各种级别的间接。