简体   繁体   English

Python重写__init__

[英]Python overriding __init__

I know that plenty of people ask questions on this subject, but I haven't seen my specific one asked. 我知道有很多人就这个问题提出问题,但我没有看到我的具体问题。 When subclassing you can override __init__() the same way that you can override any other method. 子类化时,您可以覆盖__init__() ,就像覆盖任何其他方法一样。 My question is why in the example below this doesn't seem to be working correctly: 我的问题是为什么在下面的例子中这似乎没有正常工作:

import random
class MyRand(random.Random):
    def __init__(self, myvar1, myvar2, x=None):
        # ( ... my code ...)
        super(MyRand, self).__init__(x)

Remember that Random 's constructor has the following signature: __init__(self, x=None) where x is an optional seed. 请记住, Random的构造函数具有以下签名: __init__(self, x=None)其中x是可选种子。 I want to keep that feature in my subclass, but also I want to require two mandatory variables, myvar1 and myvar2 . 我想在我的子类中保留该功能,但我还想要两个必需变量myvar1myvar2

However, when you try and instantiate (without a seed) you get an error: 但是,当您尝试实例化(没有种子)时会出现错误:

MyRand('var1', 'var2')
TypeError: seed expected at most 1 arguments, got 2

This is because python thinks you want Random 's constructor and passes your two arguments 'var1' and 'var2' as the seed. 这是因为python认为你想要Random的构造函数并将你的两个参数'var1'和'var2'作为种子传递。 The seed (which is called from inside Random 's constructor) only wants 1 argument, and so you get an error. 种子(从Random的构造函数中调用)只需要1个参数,因此会出错。

However, if you do 但是,如果你这样做

MyRand(myvar1='var1', myvar2='var2')

This works, here python understands that you're passing it your two mandatory variables and not passing it the optional seed. 这是有效的,这里python知道你传递它的两个必需变量而不传递可选种子。

But I think the first case should work too. 但我认为第一种情况也应该奏效。 What's going on? 这是怎么回事?

In Python two methods are called when a object is created. 在Python中,在创建对象时会调用两个方法。 __new__ and __init__ . __new____init__ Like many classes implemented in C, random.Random uses __new__ to initialize itself (see random_new ). 像在C中实现的许多类一样, random.Random使用__new__来初始化自己(参见random_new )。 You have to overwrite it and call it with the appropriate parameters: 您必须覆盖它并使用适当的参数调用它:

import random

class MyRand(random.Random):
    def __new__(cls, myvar1, myvar2, x=None):
        return random.Random.__new__(cls, x)

    def __init__(self, myvar1, myvar2, x=None):
        # ( ... my code ...)

You've mis-diagnosed the problem a little. 你错误地诊断了这个问题。 The problem is that random.Random 's initialization isn't entirely contained in random.Random.__init__ . 问题是random.Random的初始化并不完全包含在random.Random.__init__ It also inherits _random.Random.__new__ : 它还继承了_random.Random.__new__

static PyObject *
random_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    RandomObject *self;
    PyObject *tmp;

    if (type == &Random_Type && !_PyArg_NoKeywords("Random()", kwds))
        return NULL;

    self = (RandomObject *)type->tp_alloc(type, 0);
    if (self == NULL)
        return NULL;
    tmp = random_seed(self, args);
    if (tmp == NULL) {
        Py_DECREF(self);
        return NULL;
    }
    Py_DECREF(tmp);
    return (PyObject *)self;
}

You're going to have to override __new__ , too, and only pass the seed argument it expects, positionally (because it doesn't understand it as a keyword argument). 您将不得不重写__new__ ,并且仅在位置上传递它期望的seed参数(因为它不将其理解为关键字参数)。

They really shouldn't be mixing __init__ and __new__ like this. 他们真的不应该像这样混合__init____new__ Initialization order gets really weird when you do that. 当你这样做时,初始化顺序变得非常奇怪。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM